how to reorder an item in itemscontrol by holding in item? - xaml

HI i try to reorder items in ItemsControl . when i set ManipulationMode of element in ItemsControl to ManipulationModes.TranslateY ScrollView dosent work. for this problem i change this ManipulationMode in Holding event but i faced a new problem.
in my code,we need release finger after holding and touch again for moving. i need holding and moving finger to drag items not holding and release and touch again and moving. this release is to bad for me and users
please help me.
my code:
<ItemsControl ItemsSource="{Binding Items}"
x:Name="todoList">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Background="{Binding Path=color, Converter={StaticResource ColorToBrushConverter}}"
Height="75"
x:Name="todoItem">
<i:Interaction.Behaviors>
<Behaviors:DragReOrderBehavior />
</i:Interaction.Behaviors>
<Grid Background="{StaticResource itemGradient}">
<!--task text-->
<TextBlock Text="{Binding Title}"
Margin="15,15,0,15" FontSize="25" TextWrapping="Wrap"
x:Name="taskText"/>
</Grid>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
and behavior:
public class DragReOrderBehavior : DependencyObject, IBehavior
{
private static readonly int AutoScrollHitRegionSize = 80;
private DispatcherTimer _autoScrollTimer;
private FrameworkElement _dragItem;
private int _initialDragIndex;
private bool IsActive = false;
private ItemsControl itemscontrolList;
private ItemViewModel draggedItemVM;
private MainViewModel VM;
private ResettableObservableCollection<ItemViewModel> itemsListVm;
private ScrollViewer _scrollViewer;
// private SoundEffect _moveSound;
public DependencyObject AssociatedObject { get; private set; }
public void Attach(DependencyObject associatedObject)
{
AssociatedObject = associatedObject;
var fw = (FrameworkElement)AssociatedObject;
//fw.ManipulationMode = ManipulationModes.TranslateY | ManipulationModes.System;
////fw.ManipulationStarted += fw_ManipulationStarted;
fw.Holding += fw_Holding;
//fw.ManipulationDelta += fw_ManipulationDelta;
//fw.ManipulationCompleted += fw_ManipulationCompleted;
if (fw.RenderTransform == null || fw.RenderTransform as TranslateTransform == null)
{
fw.RenderTransform = new TranslateTransform();
}
// a timer which is used to periodically detect the position of the
// item being dragged in order to allow auto-scroll behaviour
_autoScrollTimer = new DispatcherTimer();
_autoScrollTimer.Interval = TimeSpan.FromMilliseconds(50);
_autoScrollTimer.Tick += (s, e) =>
{
AutoScrollList();
ShuffleItemsOnDrag();
};
// _moveSound = SoundEffect.FromStream(TitleContainer.OpenStream("Sounds/Windows XP Menu Command.wav"));
}
void fw_Holding(object sender, HoldingRoutedEventArgs e)
{
//if (Math.Abs(e.Cumulative.Translation.Y) > Math.Abs(e.Cumulative.Translation.X))
// {
//var fw = (FrameworkElement)AssociatedObject;
//fw.ManipulationMode = ManipulationModes.TranslateRailsY | ManipulationModes.System;
IsActive = true;
// locate the element being dragged
_dragItem = AssociatedObject as FrameworkElement;
itemscontrolList = AssociatedObject.Ancestors<ItemsControl>().OfType<ItemsControl>().FirstOrDefault();
draggedItemVM = ((ItemViewModel)_dragItem.DataContext);
VM = (MainViewModel)itemscontrolList.DataContext;
itemsListVm = VM.Items;
_scrollViewer = itemscontrolList.Descendants<ScrollViewer>()
.Cast<ScrollViewer>()
.SingleOrDefault();
_dragItem.SetVerticalOffset(0);
_dragItem.ManipulationMode = ManipulationModes.TranslateY;
_dragItem.ManipulationDelta += fw_ManipulationDelta;
_dragItem.ManipulationCompleted += fw_ManipulationCompleted;
_dragItem.UpdateLayout();
itemscontrolList.UpdateLayout();
_initialDragIndex = itemsListVm.IndexOf(draggedItemVM);
// fade out the items in the list, other than the dragged one
foreach (var item in itemscontrolList.GetItemsInView()
.Where(i => i.DataContext != draggedItemVM))
{
item.Animate(1.0, 0.7, "Opacity", 300, 0);
}
_autoScrollTimer.Start();
// }
}
}

The ListView & GridView support reordering items. How about thinking of using them?
First you can disable this feature by setting CanDragItems CanReorderItems AllowDrop to false and when you hold the item in your ListView then setting the properties above to true which will enable the Reorder feature.

Related

Xamarin Forms: Not able to update the custom control on the UI

I have created a custom control that has horizontal bar there can be N number of boxview in the bar based on number I get from API for example i have a control with limit of 20 controls and i have selected 10 of them so 10 boxview will be on orange and remaining 10 from 20 will be black
i need to update control on every checkbox selection and it is working fine for me till i go to next screen and come back to the same screen once i come back to this screen control stops updating wile debug i get data in my code but its not updating on UI.
How i use it in my code
<views:CustomDashControl
x:Name="customDash"
Grid.Row="2"
Grid.ColumnSpan="3"
HorizontalOptions="FillAndExpand"
ItemsSource="{Binding ControlData}"
VerticalOptions="Start" />
My CustomControl XAML
<ContentView
x:Class="LIRAppV1.Controls.CustomDashControl"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
<StackLayout
Padding="1"
BackgroundColor="White"
HorizontalOptions="CenterAndExpand"
VerticalOptions="FillAndExpand">
<!--<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>-->
<Grid
x:Name="progressbar"
BackgroundColor="Transparent"
ColumnSpacing="0"
HorizontalOptions="FillAndExpand"
VerticalOptions="Start">
<Grid.RowDefinitions>
<RowDefinition Height="20" />
</Grid.RowDefinitions>
</Grid>
</StackLayout>
</ContentView>
My CodeBehind of custom control
public partial class CustomDashControl : ContentView
{
static int totalCount;
static Color barColor;
private static ObservableCollection<CustomControlData> tempData;
public static ObservableCollection<CustomControlData> TempData
{
get { return tempData; }
set
{
tempData = value;
customDashControl.OnPropertyChanged("TempData");
}
}
static CustomDashControl customDashControl;
public CustomDashControl()
{
try
{
InitializeComponent();
customDashControl = this;
}
catch (Exception ex)
{
BaseViewModel.HandleException(ex);
}
}
#region Bindable Properties
public static readonly BindableProperty ItemsSourceProperty =
BindableProperty.Create("ItemsSource",
typeof(ObservableCollection<CustomControlData>),
typeof(CustomDashControl), new
ObservableCollection<CustomControlData>(),
BindingMode.Default, null, OnItemsSourceChanged);
private static void OnItemsSourceChanged(BindableObject bindable, object oldValue, object newValue)
{
if (oldValue != newValue)
{
(bindable as CustomDashControl).OnPropertyChanged("ItemsSource");
TempData = (ObservableCollection<CustomControlData>)newValue;
UpdateBar();
}
}
private static void UpdateBar()
{
try
{
if (TempData != null && TempData.Count > 0)
{
var control = customDashControl.progressbar;
control.ColumnDefinitions.Clear();
control.Children.Clear();
//Working
for (int i = 0, j = 0; i < TempData.Count; i++, j++)
{
control.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Auto });
var tempBox = new BoxView() { Color = TempData[i].BarColor, WidthRequest = TempData[i].BarWidth };
control.Children.Add(tempBox, j, 0);
j++;
control.ColumnDefinitions.Add(new ColumnDefinition() { Width = 1 });
control.Children.Add(new BoxView() { Color = Color.White, WidthRequest = 1 }, (j), 0);
}
Console.WriteLine(control.Children);
}
}
catch (Exception ex)
{
BaseViewModel.HandleException(ex);
}
}
public ObservableCollection<CustomControlData> ItemsSource
{
get { return (ObservableCollection<CustomControlData>)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
public static readonly BindableProperty TotalCountProperty = BindableProperty.Create(propertyName: "TotalCount", returnType: typeof(int), declaringType: typeof(CustomDashControl), defaultValue: 0, propertyChanged: propertyChanges1);
private static void propertyChanges1(BindableObject bindable, object oldValue, object newValue)
{
if (oldValue != newValue)
{
var control = bindable as CustomDashControl;
totalCount = (int)newValue;
if (totalCount > 0)
{
(customDashControl.BindingContext as CustomDashControlViewModel).totalCount = totalCount;
}
}
}
public int TotalCount
{
get { return (int)GetValue(TotalCountProperty); }
set { SetValue(TotalCountProperty, value); }
}
#endregion
}
OnAppearing will be executed before the screen comes, when you want an Loaded event that needs to be executed right after the screen comes, there is a workaround.
Create an property in viewmodel like below.
private bool _toggleTemp;
public bool ToggleTemp
{
get => _toggleTemp;
set => SetProperty(ref _toggleTemp, value);
}
Add the following line to the last line of the constructor.
LoadingVm.ToggleTemp = true;
Add an Switch to your screen and make IsVisible to false as below.
<Switch IsToggled="{Binding ToggleTemp}" Toggled="Switch_OnToggled" IsVisible="False" />
Now you can write the code that you want to write in Page Loaded in Switch_OnToggled.
private async void Switch_OnToggled(object sender, ToggledEventArgs e)
{
/* Your code goes here... */
}
Thanks!
If this does not work refer this --
In the onappearing I wrapped everything in an async call and waited a few hundred ms for the page to get rendered.
await WaitAndExecute(1000, () =>
{
// refresh code
}
protected async Task WaitAndExecute(int milisec, Action actionToExecute)
{
await Task.Delay(milisec);
actionToExecute();
}
https://forums.xamarin.com/discussion/22561/page-loaded-event

How to display a label with click on listview

I want to show a label when i click on my item in my listview.
The real problem i don't know how to link between my viewmodel and my views
I want modify my label in viewmodel but I don't know if its possible currently.
My xaml :
<StackLayout>
<Label x:Name="labelperso"
Text="{Binding newProduct}"
IsVisible="{Binding Addproduct}"
VerticalTextAlignment="Center"
HorizontalTextAlignment="Center"
BackgroundColor="#000000"
FontSize="20"
Opacity="0"/>
<ListView ItemsSource="{Binding Products}" CachingStrategy="RecycleElement" RowHeight="50" >
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding CodeReferenceLibelle}" TextColor="Black"/>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.Behaviors>
<b:EventToCommandBehavior EventName="ItemSelected" Command="{Binding
SelectCommand}" Converter="{StaticResource SelectedItemConverter}"/>
</ListView.Behaviors>
my viewmodel :
#region labelperso property
private string _newProduct;
public string newProduct
{
get { return _newProduct; }
set { SetProperty(ref _newProduct, value); }
}
#endregion
#region Addproduct property
private bool _Addproduct;
public bool Addproduct
{
get { return _Addproduct; }
set { SetProperty(ref _Addproduct, value); }
}
#endregion
when I click on my item :
async Task Select()
{
newProduct = "Produit ajouté !";
basketManager.AddProductSkuAsync(sku);
newProduct = "";
await Task.Run(() => ShowText());
}
//I have tried this but I can't use my label in my view
async Task ShowText()
{
await labelperso.FadeTo(1);
await Task.Delay(1000);
await labelperso.FadeTo(0);
}
Why are you want to take the label "labelperso" in VM ? you can use it in xaml.cs instead.
You just need to add the event ItemSelected like this:
<ListView ItemsSource="{Binding Products}" ItemSelected="OnSelection">
In xaml.cs
void OnSelection(object sender, SelectedItemChangedEventArgs e)
{
if (e.SelectedItem == null)
{
return;
}
//suppose the binding Object is Product
Product product = (Product)e.SelectedItem;
//labelperso.Text = "name = " + product.Name;
labelperso.FadeTo(1);
Task.Delay(1000);
labelperso.FadeTo(0);
}
Normally, VM are unrelated to Xaml, and we should not get labels from VM.
And we don't recommend it.But if you must, you can pass the Label in from the xaml.cs file like this:
You can define a variable in yourpage.xaml.cs:
public Label pageLabel;
and initial like this:
pageLabel = labelperso;
BindingContext = new YourViewmodel(this);
And in YourViewmodel.cs:
public Label ss;
public YourViewmodel(ContentPage parentPage)
{// here HomePage is your contentPage name of the page`
ss = ((HomePage)parentPage).pageLabel;//after this you can use it
}
You need to add a SelectedProduct property to your VM.
private string _SelectedProduct;
public string SelectedProduct
{
get { return _SelectedProduct; }
set { SetProperty(ref _SelectedProduct, value); }
}
You can then bind your ListView's SelectedItem to it
<ListView ItemsSource="{Binding Products}"
SelectedItem="{Binding SelectedProduct}"
CachingStrategy="RecycleElement"
RowHeight="50" >
You can then control the visibility of your label by binding to SelectedProduct via a "nullToVisibility" converter, or by using triggers etc.
You should try to use MVVM pattern rather than hacking with code behind.
Using MVVM you can add a Visible property to your viewmodel and bind the IsVisible property of the label to it.
Code will be much easy to read and maintain.

User Control Animation Only Works On Last Declared Control Instance

I am proto-typing a (Windows 10 universal app) UI and have built a very simple/rough user control to act as a 'badge', i.e show a numeric value in a circle, and animate the value changing. My issue is the control works if there is only a single instance of it in an application page. If there are multiple instances (even if the other instances are invisible), then only the last declared instance animates.
I've tried declaring the animation both in the user control's XAML, and in code behind to attempt to ensure there's no cross-over/mix up with the animation being shared. I also added a change callback to the property being animated, which writes the property value out using Debug.WriteLine. For control instances that animate properly the value changes as expected, i.e if we go from 10 to 20, the property is set to 10, 11, 12, 13.... 20. For the instances that don't work, the value is just set to the from property every time, i.e 10, 10, 10, 10, 10.
Below is a sample of the user control, and then a sample page that uses three instances of it. Placing both of these is a new Windows 10 Universal app called App3 should reproduce the issue. In the sample page the first two badges don't animate properly when their button is clicked, but the last one does.
Is anyone able to point out what I'm doing wrong, and why this breaks with multiple instances on a page?
Thanks.
Note: The code has gotten quite rough as I've hacked things around trying to figure out what the issue is, and it was only prototype code to begin with, so I apologize for the mess.
<UserControl
x:Class="App3.BadgeView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App3"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="20"
d:DesignWidth="20">
<Grid>
<Ellipse x:Name="Border" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Fill="{Binding BadgeBorderBrush}" />
<Ellipse x:Name="BadgeInner" Margin="2" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Fill="{Binding BadgeFillBrush}" />
<TextBlock x:Name="BadgeValue" Margin="5" HorizontalAlignment="Center" FontSize="10" VerticalAlignment="Center" TextAlignment="Center" TextTrimming="CharacterEllipsis" Foreground="White" Text="{Binding DisplayValue}" />
</Grid>
public sealed partial class BadgeView : UserControl
{
public DependencyProperty BadgeBorderBrushProperty = DependencyProperty.Register("BadgeBorderBrush", typeof(Brush), typeof(BadgeView), new PropertyMetadata(new SolidColorBrush(Windows.UI.Colors.Yellow)));
public DependencyProperty BadgeFillBrushProperty = DependencyProperty.Register("BadgeFillBrush", typeof(Brush), typeof(BadgeView), new PropertyMetadata(new SolidColorBrush(Windows.UI.Colors.Orange)));
public DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(int), typeof(BadgeView), new PropertyMetadata(0, new PropertyChangedCallback(ValueChanged)));
public DependencyProperty DisplayValueProperty = DependencyProperty.Register("DisplayValue", typeof(int), typeof(BadgeView), new PropertyMetadata(0, DisplayValueChanged));
private static void DisplayValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
System.Diagnostics.Debug.WriteLine(((BadgeView)d).DisplayValue);
}
private Storyboard AnimateBadgeValueCount;
private DoubleAnimation BadgeValueAnimation;
public BadgeView()
{
this.InitializeComponent();
this.BadgeValue.DataContext = this.BadgeInner.DataContext = this.Border.DataContext = this;
AnimateBadgeValueCount = new Storyboard(); ;
AnimateBadgeValueCount.Duration = TimeSpan.FromSeconds(0.5);
Storyboard.AllowDependentAnimations = true;
BadgeValueAnimation = new DoubleAnimation();
BadgeValueAnimation.Duration = TimeSpan.FromSeconds(0.5);
BadgeValueAnimation.EnableDependentAnimation = true;
BadgeValueAnimation.EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseOut };
this.AnimateBadgeValueCount.FillBehavior = FillBehavior.Stop;
this.BadgeValueAnimation.FillBehavior = FillBehavior.Stop;
AnimateBadgeValueCount.Children.Add(BadgeValueAnimation);
Storyboard.SetTarget(AnimateBadgeValueCount, this);
Storyboard.SetTargetProperty(AnimateBadgeValueCount, "DisplayValue");
this.AnimateBadgeValueCount.Completed += AnimateBadgeValueCount_Completed;
}
private void AnimateBadgeValueCount_Completed(object sender, object e)
{
this.DisplayValue = this.Value;
}
private static void ValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var badgeView = (BadgeView)d;
badgeView.AnimateValue();
}
private void AnimateValue()
{
if (Value != DisplayValue)
{
this.BadgeValue.DataContext = this.BadgeInner.DataContext = this.Border.DataContext = this;
this.AnimateBadgeValueCount.Stop();
this.BadgeValueAnimation.From = this.DisplayValue;
this.BadgeValueAnimation.To = this.Value;
this.BadgeValueAnimation.FillBehavior = FillBehavior.Stop;
//Storyboard.SetTarget(this.AnimateBadgeValueCount, this);
//Storyboard.SetTargetProperty(this.AnimateBadgeValueCount, "DisplayValue");
this.AnimateBadgeValueCount.Begin();
}
}
public Brush BadgeBorderBrush
{
get { return (Brush)this.GetValue(this.BadgeBorderBrushProperty); }
set
{
this.SetValue(this.BadgeBorderBrushProperty, value);
}
}
public Brush BadgeFillBrush
{
get { return (Brush)this.GetValue(this.BadgeFillBrushProperty); }
set
{
this.SetValue(this.BadgeFillBrushProperty, value);
}
}
public int Value
{
get { return (int)this.GetValue(ValueProperty); }
set
{
this.SetValue(ValueProperty, value);
}
}
public int DisplayValue
{
get { return (int)this.GetValue(DisplayValueProperty); }
set
{
this.SetValue(DisplayValueProperty, value);
}
}
}
<Page
x:Class="App3.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App3"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<StackPanel Orientation="Vertical">
<Button Content="Do it" x:Name="DoIt1" Click="DoIt1_Click" />
<local:BadgeView x:Name="Badge1" Width="20" Height="20" BadgeFillBrush="Blue" />
<Button Content="Do it" x:Name="DoIt2" Click="DoIt2_Click" />
<local:BadgeView x:Name="Badge2" Width="20" Height="20" />
<Button Content="Do it" x:Name="DoIt3" Click="DoIt3_Click" />
<local:BadgeView x:Name="Badge3" Width="20" Height="20" />
</StackPanel>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
private void DoIt1_Click(object sender, RoutedEventArgs e)
{
this.Badge1.Value += 10;
}
private void DoIt2_Click(object sender, RoutedEventArgs e)
{
this.Badge2.Value += 10;
}
private void DoIt3_Click(object sender, RoutedEventArgs e)
{
this.Badge3.Value += 10;
}
}
What I have done is simplify code and simplify and move the datacontext inside the loaded event inside the constructor:
this.Loaded += (s, e) =>
{
this.DataContext = this;
AnimateBadgeValueCount = new Storyboard(); ;
AnimateBadgeValueCount.Duration = TimeSpan.FromSeconds(0.5);
BadgeValueAnimation = new DoubleAnimation();
BadgeValueAnimation.Duration = TimeSpan.FromSeconds(0.5);
//BadgeValueAnimation.EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseOut };
AnimateBadgeValueCount.Children.Add(BadgeValueAnimation);
Storyboard.SetTarget(AnimateBadgeValueCount, this);
Storyboard.SetTargetProperty(AnimateBadgeValueCount, "DisplayValue");
this.AnimateBadgeValueCount.Completed += AnimateBadgeValueCount_Completed;
};
private async void AnimateValue()
{
if (Value != DisplayValue)
{
this.AnimateBadgeValueCount.Stop();
this.BadgeValueAnimation.From = this.DisplayValue;
this.BadgeValueAnimation.To = this.Value;
BadgeValueAnimation.EnableDependentAnimation = true;
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.High, () =>
{
this.AnimateBadgeValueCount.Begin();
});
}
}
I have commented the EasingFunction, it works but in my opinion fit betters.
It is curious, because if I set the datacontext just in the constructor it works bad, but inside goes fine.
Tell me if you try.

Child controls grow unlimited in custom XAML control. What's wrong?

I've implemented a Windows 8 XAML VisibilitySwitchControl that displays the first child on certain condition; otherwise the other controls are shown. The code is as follows
[ContentProperty(Name = "Items")]
public class VisibilitySwitchControl : ItemsControl
{
public VisibilitySwitchControl()
{
DefaultStyleKey = typeof(VisibilitySwitchControl);
if (Items != null)
Items.VectorChanged += OnItemsChanged;
}
public bool ShowFirst
{
get { return (bool)GetValue(ShowFirstProperty); }
set { SetValue(ShowFirstProperty, value); }
}
public static readonly DependencyProperty ShowFirstProperty =
DependencyProperty.Register("ShowFirst", typeof(bool), typeof(VisibilitySwitchControl), new PropertyMetadata(true, OnShowFirstChanged));
public object VisibleContent
{
get { return GetValue(VisibleContentProperty); }
private set { SetValue(VisibleContentProperty, value); }
}
public static readonly DependencyProperty VisibleContentProperty =
DependencyProperty.Register("VisibleContent", typeof(object), typeof(VisibilitySwitchControl), new PropertyMetadata(null));
private static void OnShowFirstChanged(DependencyObject d, DependencyPropertyChangedEventArgs args)
{
var visibilityItemsControl = d as VisibilitySwitchControl;
if (visibilityItemsControl != null)
{
visibilityItemsControl.Evaluate();
}
}
void OnItemsChanged(IObservableVector<object> sender, IVectorChangedEventArgs evt)
{
Evaluate();
}
void Evaluate()
{
if (Items != null && Items.Any())
{
var controls = Items.OfType<FrameworkElement>().ToList();
for (var i = 0; i < controls.Count; i++)
{
if (i == 0)
{
VisibleContent = controls[i];
controls[i].Visibility = ShowFirst ? Visibility.Visible : Visibility.Collapsed;
}
else
{
controls[i].Visibility = !ShowFirst ? Visibility.Visible : Visibility.Collapsed;
}
}
}
else
{
VisibleContent = null;
}
}
}
However, if I place two ListView controls inside my VisibilitySwitchControl the ListView can grow in way that it is larger than the page and no scrollbars are shown. It doesn't stop a the parent containers bounds.
<custom:VisibilitySwitchControl ShowFirst="{Binding Path=IsFirstLevelNav}">
<ListView x:Name="FirstListView"
VerticalAlignment="Stretch"
ItemsSource="{Binding ...}"
SelectedItem="{Binding ..., Mode=TwoWay}"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
/>
<ListView x:Name="SecondListView"
VerticalAlignment="Stretch"
ItemsSource="{Binding ...}"
SelectedItem="{Binding ..., Mode=TwoWay}"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
/>
</custom:VisibilitySwitchControl>
How can I enforce a VerticalAlignment="Stretch" behavior of the children? If I remove my control and place only one the lists directly in the code, everything works as expected.
Thanks for suggestions.
you want to stretch the Height of the listview try binding it to the actual height of the parent
Heres the code part you need to include
Height="{Binding ActualHeight, ElementName=parentContainer}"
where parentContainer is the name of the custom:VisibilitySwitchControl you are using . this will bind the height to the parent container's display height. Try and let me know
If what you want is that you scroll one ListView and then when you reach the end it show the second ListView then you just need to add a ScrollViewer around the ItemPresenter inside the style of VisibilitySwitchControl and disable the ListView ScrollViewer. Just note that it mean that you will lost the virtualisation inside the ListView.
If what you want is each ListView taking half the screen than the easiest is probably to just set a Fix height for each items depending on Window.Current.Bounds.Height and register for Window.Current.SizeChanged to update it when the windows heigh changed (make sure to unregister it in unloaded to prevent memory leak).
An alternative which I think would be more complicated, would be to change the ItemsPanel of VisibilitySwitchControl to something else (by default it is a Stack panel so it will grow larger than the screen) like for example to a Grid in which you set as many row with star heigh as items you have (and then you will need to set the row of each item) or by creating a custom Panel.

Autocompletebox SelectedText Bug

I want to bind both the SelectedText and SelectedItem properties of an AutocompleteBox because my client wants to be able to input text and select from the list also. It's working properly but ...
The MainPage has one DataGrid. When I select a record from the Grid (i.e. SelectedItem), I want to set it in a popup window's AutocompleteBox. Some times it works but some times it doesn't.
What should I do for this issue?
This is my XAML:
<Sdk:AutoCompleteBox Grid.Column="3" Grid.Row="3" Height="18" Width="150"
IsTextCompletionEnabled="True" TabIndex="9" HorizontalAlignment="Left"
Text="{Binding ElementName=ResEdit,Path=DataContext.SelectedDemoText,Mode=TwoWay}"
ItemsSource="{Binding ElementName=ResEdit,Path=DataContext.DemoList,Mode=OneWay}"
ItemTemplate="{StaticResource DemoTemplate}"
ValueMemberPath="DemoCode"
LostFocus="AutoCompleteBox_LostFocus"
Margin="0,0,21,0" Padding="0">
</Sdk:AutoCompleteBox>
This property is in my view-model and bound to the DataGrid:
public InvoicesDTO SelectedInvoice
{
get { return _selectedInvoice; }
set
{
SelectedInvoice = value;
SelectedDomoText = SelectedInvoice.DemoText.Trim();
RaisePropertyChanged("SelectedInvoice");
}
}
You should not use both function SelectedText and SelectedItem in autocomplete. it's a bug of AutoCompleteBox..... A better way is to set the visiblity of the textbox and AutoCompleteBox on GotFocus and LossFocus. This Way You Will Defiantly Solve You Problem
private void DemoAutoComplete_LostFocus(object sender, RoutedEventArgs e)
{
DemoTextBox.Visibility = Visibility.Visible;
DemoAutoComplete.Visibility = Visibility.Collapsed;
DemoTextBox.Text = OCRAutoComplete.Text;
((DemoVM)this.DataContext).SelectedDemoText = DemoAutoComplete.Text;
}
private void DemoTextBox_GotFocus(object sender, RoutedEventArgs e)
{
DemoAutoComplete.Text = OctTextBox.Text;
DemoTextBox.Visibility = Visibility.Collapsed;
DemoAutoComplete.Visibility = Visibility.Visible;
DemoAutoComplete.Focus();
}