UWP TreeView sort leads to random events - c#

Team,
I run in a very weird issue with treeview.
Here are the steps to rep:
1. create a new project
2. select Window Studio Template
3. Select MVVM Light
4. Add treeview page
5. create project
6. Open TreeViewPage.xaml and add with:
xmlns:Custom="using:Microsoft.UI.Xaml.Controls"
xmlns:helper="using:TitoDoc2020.Helpers"
<Page.Resources>
<Style x:Key="RadioButtonRevealStyle" TargetType="RadioButton">
<Setter Property="Background" Value="{ThemeResource ToggleButtonRevealBackground}" />
<Setter Property="Foreground" Value="{ThemeResource ToggleButtonForeground}" />
<Setter Property="BorderBrush" Value="{ThemeResource ToggleButtonRevealBorderBrush}" />
<Setter Property="BorderThickness" Value="{ThemeResource ToggleButtonRevealBorderThemeThickness}" />
<Setter Property="Padding" Value="{ThemeResource ButtonPadding}" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
<Setter Property="UseSystemFocusVisuals" Value="{StaticResource UseSystemFocusVisuals}" />
<Setter Property="FocusVisualMargin" Value="-3" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="RadioButton">
<Grid
x:Name="RootGrid"
Background="{TemplateBinding Background}"
CornerRadius="{TemplateBinding CornerRadius}">
<ContentPresenter
x:Name="ContentPresenter"
Padding="{TemplateBinding Padding}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
AutomationProperties.AccessibilityView="Raw"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
ContentTransitions="{TemplateBinding ContentTransitions}"
CornerRadius="{TemplateBinding CornerRadius}" />
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<Storyboard>
<PointerUpThemeAnimation Storyboard.TargetName="RootGrid" />
</Storyboard>
</VisualState>
<VisualState x:Name="PointerOver">
<VisualState.Setters>
<Setter Target="RootGrid.(RevealBrush.State)" Value="PointerOver" />
<Setter Target="RootGrid.Background" Value="{ThemeResource ToggleButtonRevealBackgroundPointerOver}" />
<Setter Target="ContentPresenter.BorderBrush" Value="{ThemeResource ToggleButtonRevealBorderBrushPointerOver}" />
<Setter Target="ContentPresenter.Foreground" Value="{ThemeResource ToggleButtonForegroundPointerOver}" />
</VisualState.Setters>
<Storyboard>
<PointerUpThemeAnimation Storyboard.TargetName="RootGrid" />
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<VisualState.Setters>
<Setter Target="RootGrid.(RevealBrush.State)" Value="Pressed" />
<Setter Target="RootGrid.Background" Value="{ThemeResource ToggleButtonRevealBackgroundPressed}" />
<Setter Target="ContentPresenter.BorderBrush" Value="{ThemeResource ToggleButtonRevealBorderBrushPressed}" />
<Setter Target="ContentPresenter.Foreground" Value="{ThemeResource ToggleButtonForegroundPressed}" />
</VisualState.Setters>
<Storyboard>
<PointerDownThemeAnimation Storyboard.TargetName="RootGrid" />
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Target="RootGrid.Background" Value="{ThemeResource ToggleButtonRevealBackgroundDisabled}" />
<Setter Target="ContentPresenter.BorderBrush" Value="{ThemeResource ToggleButtonRevealBorderBrushDisabled}" />
<Setter Target="ContentPresenter.Foreground" Value="{ThemeResource ToggleButtonForegroundDisabled}" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Checked">
<VisualState.Setters>
<Setter Target="RootGrid.Background" Value="{ThemeResource ToggleButtonRevealBackgroundChecked}" />
<Setter Target="ContentPresenter.BorderBrush" Value="{ThemeResource ToggleButtonRevealBorderBrushChecked}" />
<Setter Target="ContentPresenter.Foreground" Value="{ThemeResource ToggleButtonForegroundChecked}" />
</VisualState.Setters>
<Storyboard>
<PointerUpThemeAnimation Storyboard.TargetName="RootGrid" />
</Storyboard>
</VisualState>
<VisualState x:Name="CheckedPointerOver">
<VisualState.Setters>
<Setter Target="RootGrid.(RevealBrush.State)" Value="PointerOver" />
<Setter Target="RootGrid.Background" Value="{ThemeResource ToggleButtonRevealBackgroundCheckedPointerOver}" />
<Setter Target="ContentPresenter.BorderBrush" Value="{ThemeResource ToggleButtonRevealBorderBrushCheckedPointerOver}" />
<Setter Target="ContentPresenter.Foreground" Value="{ThemeResource ToggleButtonForegroundCheckedPointerOver}" />
</VisualState.Setters>
<Storyboard>
<PointerUpThemeAnimation Storyboard.TargetName="RootGrid" />
</Storyboard>
</VisualState>
<VisualState x:Name="CheckedPressed">
<VisualState.Setters>
<Setter Target="RootGrid.(RevealBrush.State)" Value="Pressed" />
<Setter Target="RootGrid.Background" Value="{ThemeResource ToggleButtonRevealBackgroundCheckedPressed}" />
<Setter Target="ContentPresenter.BorderBrush" Value="{ThemeResource ToggleButtonRevealBorderBrushCheckedPressed}" />
<Setter Target="ContentPresenter.Foreground" Value="{ThemeResource ToggleButtonForegroundCheckedPressed}" />
</VisualState.Setters>
<Storyboard>
<PointerDownThemeAnimation Storyboard.TargetName="RootGrid" />
</Storyboard>
</VisualState>
<VisualState x:Name="CheckedDisabled">
<VisualState.Setters>
<Setter Target="RootGrid.Background" Value="{ThemeResource ToggleButtonRevealBackgroundCheckedDisabled}" />
<Setter Target="ContentPresenter.BorderBrush" Value="{ThemeResource ToggleButtonRevealBorderBrushCheckedDisabled}" />
<Setter Target="ContentPresenter.Foreground" Value="{ThemeResource ToggleButtonForegroundCheckedDisabled}" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Indeterminate">
<VisualState.Setters>
<Setter Target="RootGrid.Background" Value="{ThemeResource ToggleButtonRevealBackgroundIndeterminate}" />
<Setter Target="ContentPresenter.BorderBrush" Value="{ThemeResource ToggleButtonRevealBorderBrushIndeterminate}" />
<Setter Target="ContentPresenter.Foreground" Value="{ThemeResource ToggleButtonForegroundIndeterminate}" />
</VisualState.Setters>
<Storyboard>
<PointerUpThemeAnimation Storyboard.TargetName="RootGrid" />
</Storyboard>
</VisualState>
<VisualState x:Name="IndeterminatePointerOver">
<VisualState.Setters>
<Setter Target="RootGrid.(RevealBrush.State)" Value="PointerOver" />
<Setter Target="RootGrid.Background" Value="{ThemeResource ToggleButtonRevealBackgroundIndeterminatePointerOver}" />
<Setter Target="ContentPresenter.BorderBrush" Value="{ThemeResource ToggleButtonRevealBorderBrushIndeterminatePointerOver}" />
<Setter Target="ContentPresenter.Foreground" Value="{ThemeResource ToggleButtonForegroundIndeterminatePointerOver}" />
</VisualState.Setters>
<Storyboard>
<PointerUpThemeAnimation Storyboard.TargetName="RootGrid" />
</Storyboard>
</VisualState>
<VisualState x:Name="IndeterminatePressed">
<VisualState.Setters>
<Setter Target="RootGrid.(RevealBrush.State)" Value="Pressed" />
<Setter Target="RootGrid.Background" Value="{ThemeResource ToggleButtonRevealBackgroundIndeterminatePressed}" />
<Setter Target="ContentPresenter.BorderBrush" Value="{ThemeResource ToggleButtonRevealBorderBrushIndeterminatePressed}" />
<Setter Target="ContentPresenter.Foreground" Value="{ThemeResource ToggleButtonForegroundIndeterminatePressed}" />
</VisualState.Setters>
<Storyboard>
<PointerDownThemeAnimation Storyboard.TargetName="RootGrid" />
</Storyboard>
</VisualState>
<VisualState x:Name="IndeterminateDisabled">
<VisualState.Setters>
<Setter Target="RootGrid.Background" Value="{ThemeResource ToggleButtonRevealBackgroundIndeterminateDisabled}" />
<Setter Target="ContentPresenter.BorderBrush" Value="{ThemeResource ToggleButtonRevealBorderBrushIndeterminateDisabled}" />
<Setter Target="ContentPresenter.Foreground" Value="{ThemeResource ToggleButtonForegroundIndeterminateDisabled}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Page.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="treeViewColumn" MinWidth="150" MaxWidth="350" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState>
<VisualState.StateTriggers>
<!--641 is the default CompactModeThresholdWidth in NavigationView -->
<AdaptiveTrigger MinWindowWidth="641" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="header.Margin" Value="0,0,0,0" />
<Setter Target="treeViewColumn.Width" Value="350" />
<Setter Target="treeViewColumn.MaxWidth" Value="500" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid
Background="{ThemeResource SystemChromeMediumLowColor}">
<Grid.RowDefinitions>
<RowDefinition Height="40" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid
Margin="80,0,0,0"
x:Name="header"
Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock
x:Uid="TreeViewTitle"
Margin="{StaticResource SmallLeftMargin}"
Style="{StaticResource ListTitleStyle}"
VerticalAlignment="Center" />
<Button
Grid.Column="1"
x:Uid="TreeView_CollapseAllButton"
Content=""
FontSize="14"
Padding="{StaticResource SmallLeftRightMargin}"
VerticalAlignment="Stretch"
VerticalContentAlignment="Center"
FontFamily="Segoe MDL2 Assets"
Command="{Binding ElementName=collapseBehavior, Path=CollapseAllCommand}"
Background="Transparent" />
</Grid>
<StackPanel
Grid.Row="1"
x:DefaultBindMode="OneWay"
Orientation="Horizontal">
<Custom:RadioButtons MaxColumns="2">
<RadioButton
x:Name="SortDate"
Width="50"
Height="50"
MinWidth="50"
Margin="{StaticResource ButtonPadding}"
Background="Transparent"
Click="{x:Bind ViewModel.RadioButton_ClickAsync}"
CornerRadius="2,2,2,2"
Style="{StaticResource RadioButtonRevealStyle}"
Checked="{x:Bind ViewModel.RadioButton_Checked}">
<RadioButton.Content>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<FontIcon
Grid.Row="0"
Grid.RowSpan="2"
Grid.Column="0"
Grid.ColumnSpan="2"
FontFamily="{ThemeResource SymbolThemeFontFamily}"
FontSize="32"
Glyph="" />
<FontIcon
Grid.Row="0"
Grid.Column="1"
FontFamily="{ThemeResource SymbolThemeFontFamily}"
Foreground="Transparent"
Glyph="" />
<FontIcon
Grid.Row="1"
Grid.Column="1"
FontFamily="{ThemeResource SymbolThemeFontFamily}"
Foreground="Transparent"
Glyph="" />
<FontIcon
Grid.Row="0"
Grid.Column="1"
FontFamily="{ThemeResource SymbolThemeFontFamily}"
Foreground="Transparent"
Glyph="" />
<StackPanel Grid.Row="1" Grid.Column="0">
<FontIcon
Margin="0,6,0,0"
FontFamily="{ThemeResource SymbolThemeFontFamily}"
FontSize="12"
Foreground="{ThemeResource SystemAccentColorDark2}"
Glyph="{x:Bind ViewModel.ImageSrcD}" />
</StackPanel>
</Grid>
</RadioButton.Content>
</RadioButton>
<RadioButton
x:Name="SortAlph"
Width="50"
Height="50"
MinWidth="50"
Margin="{StaticResource ButtonPadding}"
Background="Transparent"
Click="{x:Bind ViewModel.RadioButton_ClickAsync}"
CornerRadius="2,2,2,2"
Style="{StaticResource RadioButtonRevealStyle}"
Checked="{x:Bind ViewModel.RadioButton_Checked}">
<RadioButton.Content>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<FontIcon
Grid.Row="0"
Grid.RowSpan="2"
Grid.Column="0"
Grid.ColumnSpan="2"
FontFamily="{ThemeResource SymbolThemeFontFamily}"
FontSize="32"
Glyph="" />
<FontIcon
Grid.Row="0"
Grid.Column="1"
Height="20"
VerticalAlignment="Top"
FontFamily="{ThemeResource SymbolThemeFontFamily}"
Foreground="Transparent"
Glyph="" />
<FontIcon
Grid.Row="1"
Grid.Column="1"
FontFamily="{ThemeResource SymbolThemeFontFamily}"
Foreground="Transparent"
Glyph="" />
<StackPanel Grid.Row="1" Grid.Column="0">
<FontIcon
Margin="0,6,0,0"
FontFamily="{ThemeResource SymbolThemeFontFamily}"
FontSize="12"
Foreground="{ThemeResource SystemAccentColorDark2}"
Glyph="{x:Bind ViewModel.ImageSrcA}" />
</StackPanel>
</Grid>
</RadioButton.Content>
</RadioButton>
</Custom:RadioButtons>
</StackPanel>
<winui:TreeView
x:Name="treeView"
Grid.Row="2"
SelectionMode="Single"
ItemsSource="{x:Bind ViewModel.SampleItems}"
ItemTemplateSelector="{StaticResource TreeViewTemplateSelector}">
<i:Interaction.Behaviors>
<behaviors:TreeViewCollapseBehavior x:Name="collapseBehavior" />
<ic:EventTriggerBehavior EventName="ItemInvoked">
<ic:InvokeCommandAction Command="{x:Bind ViewModel.ItemInvokedCommand}" />
</ic:EventTriggerBehavior>
</i:Interaction.Behaviors>
</winui:TreeView>
</Grid>
</Grid>
</Page>
Open TreeViewModel.cs and add replace with:
public string _sorting;
public bool _DateAsc;
public bool _AlphAsc;
public bool _SwapCheck = false;
public bool _filterData = false;
public int _filterDataSpan = 0;
public string ImageSrcD
{
get
{
if (_DateAsc)
{
return "\xF0AD";
}//SvgImageSource svgImage = new SvgImageSource(new Uri("ms-appx:///Assets/Image_16x.png"));
else
{
return "\xF0AE";
}
}
set { Set<bool>(ref _DateAsc, bool.Parse(value)); }
}
public string ImageSrcA
{
get
{
if (_AlphAsc)
{
return "\xF0AD";
}//SvgImageSource svgImage = new SvgImageSource(new Uri("ms-appx:///Assets/Image_16x.png"));
else
{
return "\xF0AE";
}
}
set { Set<bool>(ref _AlphAsc, bool.Parse(value)); }
}
public async Task LoadDataAsync()
{
var data = await SampleDataService.GetTreeViewDataAsync();
foreach (var item in data)
{
SampleItems.Add(item);
}
}
public async Task SortDataAsync()
{
var data = await SampleDataService.GetTreeViewDataAsync();
switch (_sorting)
{
default:
break;
case "SortAlph":
if (_AlphAsc)
{
data = data
.OrderBy(b => b.Country).ThenBy(b => b.CompanyName)
.ToList();
}
else
{
data = data
.OrderByDescending(b => b.Country).ThenByDescending(b => b.CompanyName)
.ToList();
}
break;
}
SelectedItem = null;
SampleItems.Clear();
foreach (var item in data)
{
SampleItems.Add(item);
}
}
public async void RadioButton_Checked(object sender, RoutedEventArgs e)
{
_SwapCheck = true;
/*string sorting = await ApplicationData.Current.LocalSettings.ReadAsync<string>("TreeViewSort");
switch (((RadioButton)sender).Name)
{
case "SortDate":
if (sorting == "SortDate")
{
return;
}
SortAlph.IsChecked = false;
break;
case "SortAlph":
if (sorting == "SortAlph")
{
return;
}
SortDate.IsChecked = false;
break;
default:
break;
}
ApplicationData.Current.LocalSettings.SaveAsync("TreeViewSort", ((ToggleButton)sender).Name);
_sorting = ((RadioButton)sender).Name;
SortTreeAsync();
//await LoadTreeAsync();
*/
}
public void RadioButton_ClickAsync(object sender, RoutedEventArgs e)
{
switch (((RadioButton)sender).Name)
{
case "SortAlph":
if (!_SwapCheck)
{
ImageSrcA = (!_AlphAsc).ToString();
}
break;
case "SortDate":
if (!_SwapCheck)
{
ImageSrcD = (!_DateAsc).ToString();
}
break;
default:
break;
}
_SwapCheck = false;
_sorting = ((RadioButton)sender).Name;
SortDataAsync();
//SortTreeAsync();
}
}
}
under Helpers folder create a class named TitoDoc2020Enums.cs paste:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TitoDoc2020.Helpers
{
public enum LoadingStatus
{
NotStarted = 0,
Loading = 1,
Loaded = 2
}
public enum VisualizationFormat
{
// Surname, Name
SurCName= 0,
// Surname Name
SurnName = 1,
// Name Surname
NameSur = 2
}
public enum Sorting
{
// Surname, Name
Surname = 0,
// Surname Name
Name = 1
}
public enum DateFilter
{
Day = 1, // 59583, // 
Week = 2, // 59584, // 
Month = 3, // 59271, // 
Year = 4, // // 
All = 0 //60041 // &#xEA89
}
}
Update all NuGet libraries and add compile
Click the right sorting icon multiple times, you can open some tree view items, everything happens... items get opened automatically, I even got the request to use the microphone
It does not seem to me I'm doing anything strange... why is so messed up?

nice to see you again, I could run this code sample and reproduce your problem easily. The problem is that you have not specific bool IsExpanded property for the model and bind it to TreeViewItem IsExpanded property. When you reorder the data current UI state will be covered by previous.
Please add the following to your model class and bind IsExpanded in xaml code.
public class SampleCompany : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private bool isExpanded;
public bool IsExpanded
{
get { return isExpanded; }
set
{
if (isExpanded != value)
{
isExpanded = value;
NotifyPropertyChanged("IsExpanded");
}
}
}
}
public class SampleOrder : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private bool isExpanded;
public bool IsExpanded
{
get { return isExpanded; }
set
{
if (isExpanded != value)
{
isExpanded = value;
NotifyPropertyChanged("IsExpanded");
}
}
}
}
Xaml code
<DataTemplate x:Key="CompanyTemplate" x:DataType="model:SampleCompany">
<winui:TreeViewItem
AutomationProperties.Name="{x:Bind CompanyName}"
IsExpanded="{x:Bind IsExpanded, Mode=OneWay}"
ItemsSource="{x:Bind Orders}">
<TextBlock Margin="{StaticResource XXSmallTopRightBottomMargin}" Text="{x:Bind CompanyName}" />
</winui:TreeViewItem>
</DataTemplate>
<DataTemplate x:Key="OrderTemplate" x:DataType="model:SampleOrder">
<winui:TreeViewItem
AutomationProperties.Name="{x:Bind OrderID}"
IsExpanded="{x:Bind IsExpanded, Mode=OneWay}"
ItemsSource="{x:Bind Details}">
<TextBlock Margin="{StaticResource XXSmallTopRightBottomMargin}" Text="{x:Bind ShortDescription}" />
</winui:TreeViewItem>
</DataTemplate>
Update
I've added the code but the Set part is never used and the Get part is read only when the parent is accessed
It's by-design, because, we use OneWay model, it will not edit the model property when you expand the tree view node. If we set it as TwoWay model set method will called.
BUT now the issue is that when I re-create the object I loose the status so they are all closed again.
When we re-create object but not specific IsExpanded value (default value is false),so all the nodes will close by default.

Related

Unhandled exception `The parameter is incorrect` in NotifyCollectionChangedEvent handler

I have a very simple ListView whose ItemsSource is a ObservableCollection. Better show it with code:
MainPage.xaml:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Windows.UI.Xaml.Shapes"
x:Class="Test.MainPage" Background="Black" >
<Grid x:Name="Board" Background="Transparent" >
<ListView ItemsSource="{x:Bind LineList}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Line">
<StackPanel Orientation="Horizontal" Spacing="5">
<TextBlock Foreground="White" Text="{x:Bind Name}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
Mainpage.xaml.cs:
public sealed partial class MainPage : Page
{
public ObservableCollection<Line> LineList = new ObservableCollection<Line>();
public MainPage()
{
InitializeComponent();
LineList.CollectionChanged += List_CollectionChanged;
LineList.Add(new Line { Name = "Line1" });
LineList.Add(new Line { Name = "Line2" });
}
private void List_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if(e.Action == NotifyCollectionChangedAction.Add)
{
Board.Children.Add(e.NewItems[0] as Line);//if I comment out this line, no exception
}
}
}
What I actually want is that, when I add a Line on the ListView to show it's Name, it be also added in the Grid as an actual Shape. Note that, I am using the ListView only to show the Names of those Lines, and in the Grid I want an actual Line Shape
I don't know what I've done wrong, but the above attempt gives the stated Exception.
If these informations help:
No Exception occurs if I don't add the Line in the Grid
No Exception if : Board.Children.Add(new Line { Name = "Line2" });
I've been fiddling around with your code and I was able to track down what is wrong with your code. However I'm not really sure why it's happening.
The reason why you're getting errors is because you're trying to use same instance of an UIElement (i.e. Line) that you're binding to your ListView.ItemsSource. Why it's failing, is a bit of mystery to me. I suspect that it's forbidden to Bind and add the same UIElement to XAML, as it might create binding loops!? That's just a wild guess though. Anyways...
You shouldn't be using UIElement as the binding context - I can't think of any scenario that you would do such thing. You will be better off by creating a separate model, as per my previous answer (e.g. LineViewModel), and using that as your BindingContext. Your MainPage.xaml.cs code could look like this:
public sealed partial class MainPage : Page
{
public ObservableCollection<LineViewModel> Lines = new ObservableCollection<LineViewModel>();
public MainPage()
{
InitializeComponent();
Lines.CollectionChanged += LinesOnCollectionChanged;
Lines.Add(new LineViewModel { Name = "Line1" });
Lines.Add(new LineViewModel { Name = "Line2" });
}
private void LinesOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
MainGrid.Children.Add(new Line()
{
Name = (e.NewItems[0] as LineViewModel)?.Name ?? string.Empty,
Stroke = new SolidColorBrush(Colors.Black),
StrokeThickness = 12,
X1 = 0,
X2 = 10000
});
}
}
}
public class LineViewModel
{
public string Name { get; set; }
}
The MainPage.xaml will stay the same, as per my previous answer
I'm not sure if this is what you're after but here it goes
MainPage.xaml
<Page x:Class="App4.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App4"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Page.Resources>
<Style x:Key="LineViewItemContainerStyle"
TargetType="ListViewItem">
<Setter Property="FontFamily"
Value="{ThemeResource ContentControlThemeFontFamily}" />
<Setter Property="FontSize"
Value="{ThemeResource ControlContentThemeFontSize}" />
<Setter Property="Background"
Value="{ThemeResource ListViewItemBackground}" />
<Setter Property="Foreground"
Value="{ThemeResource ListViewItemForeground}" />
<Setter Property="TabNavigation"
Value="Local" />
<Setter Property="IsHoldingEnabled"
Value="True" />
<Setter Property="Padding"
Value="0" />
<Setter Property="HorizontalContentAlignment"
Value="Stretch" />
<Setter Property="VerticalContentAlignment"
Value="Stretch" />
<Setter Property="MinWidth"
Value="{ThemeResource ListViewItemMinWidth}" />
<Setter Property="MinHeight"
Value="{ThemeResource ListViewItemMinHeight}" />
<Setter Property="AllowDrop"
Value="False" />
<Setter Property="UseSystemFocusVisuals"
Value="True" />
<Setter Property="FocusVisualMargin"
Value="0" />
<Setter Property="FocusVisualPrimaryBrush"
Value="{ThemeResource ListViewItemFocusVisualPrimaryBrush}" />
<Setter Property="FocusVisualPrimaryThickness"
Value="2" />
<Setter Property="FocusVisualSecondaryBrush"
Value="{ThemeResource ListViewItemFocusVisualSecondaryBrush}" />
<Setter Property="FocusVisualSecondaryThickness"
Value="1" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<ListViewItemPresenter x:Name="Root"
CheckBrush="{ThemeResource ListViewItemCheckBrush}"
ContentMargin="{TemplateBinding Padding}"
CheckBoxBrush="{ThemeResource ListViewItemCheckBoxBrush}"
ContentTransitions="{TemplateBinding ContentTransitions}"
CheckMode="{ThemeResource ListViewItemCheckMode}"
DragOpacity="{ThemeResource ListViewItemDragThemeOpacity}"
DisabledOpacity="{ThemeResource ListViewItemDisabledThemeOpacity}"
DragBackground="{ThemeResource ListViewItemDragBackground}"
DragForeground="{ThemeResource ListViewItemDragForeground}"
FocusVisualSecondaryBrush="{TemplateBinding FocusVisualSecondaryBrush}"
FocusVisualPrimaryThickness="{TemplateBinding FocusVisualPrimaryThickness}"
FocusVisualSecondaryThickness="{TemplateBinding FocusVisualSecondaryThickness}"
FocusBorderBrush="{ThemeResource ListViewItemFocusBorderBrush}"
FocusVisualMargin="{TemplateBinding FocusVisualMargin}"
FocusVisualPrimaryBrush="{TemplateBinding FocusVisualPrimaryBrush}"
FocusSecondaryBorderBrush="{ThemeResource ListViewItemFocusSecondaryBorderBrush}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
Control.IsTemplateFocusTarget="True"
PressedBackground="{ThemeResource ListViewItemBackgroundPressed}"
PlaceholderBackground="{ThemeResource ListViewItemPlaceholderBackground}"
PointerOverForeground="{ThemeResource ListViewItemForegroundPointerOver}"
PointerOverBackground="{ThemeResource ListViewItemBackgroundPointerOver}"
ReorderHintOffset="{ThemeResource ListViewItemReorderHintThemeOffset}"
SelectedForeground="{ThemeResource ListViewItemForegroundSelected}"
SelectionCheckMarkVisualEnabled="{ThemeResource ListViewItemSelectionCheckMarkVisualEnabled}"
SelectedBackground="{ThemeResource ListViewItemBackgroundSelected}"
SelectedPressedBackground="{ThemeResource ListViewItemBackgroundSelectedPressed}"
SelectedPointerOverBackground="{ThemeResource ListViewItemBackgroundSelectedPointerOver}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Selected" />
<VisualState x:Name="PointerOver">
<VisualState.Setters>
<Setter Target="Root.(RevealBrush.State)"
Value="PointerOver" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="PointerOverSelected">
<VisualState.Setters>
<Setter Target="Root.(RevealBrush.State)"
Value="PointerOver" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="PointerOverPressed">
<VisualState.Setters>
<Setter Target="Root.(RevealBrush.State)"
Value="Pressed" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Pressed">
<VisualState.Setters>
<Setter Target="Root.(RevealBrush.State)"
Value="Pressed" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="PressedSelected">
<VisualState.Setters>
<Setter Target="Root.(RevealBrush.State)"
Value="Pressed" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="DisabledStates">
<VisualState x:Name="Enabled" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Target="Root.RevealBorderThickness"
Value="0" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</ListViewItemPresenter>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Page.Resources>
<Grid Background="Transparent">
<ListView ItemContainerStyle="{StaticResource LineViewItemContainerStyle}"
ItemsSource="{x:Bind Lines, Mode=OneTime}"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:LineViewModel">
<Grid x:Name="ItemGrid">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Foreground="Black"
Text="{x:Bind Name, Mode=OneWay}" />
<Border Grid.Row="1"
BorderBrush="Black"
BorderThickness="1" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Page>
MainPage.xaml.cs
public sealed partial class MainPage : Page
{
public ObservableCollection<LineViewModel> Lines = new ObservableCollection<LineViewModel>();
public MainPage()
{
InitializeComponent();
Lines.Add(new LineViewModel { Name = "Line1" });
Lines.Add(new LineViewModel { Name = "Line2" });
}
}
public class LineViewModel
{
public string Name { get; set; }
}
Note, that instead of using Line I used Border. Also, I needed to override base ListViewItemContainerStyle to set HorizontalContentAlignment and VerticalContentAlignment to Stretch, so that the DataTemplate elements can take up the entire space of the item
The result:

How to create a square button?

Thanks for #Justin XL and #grek40 help me so much.
I must apologize for my poor English that troubles everyone so much.
And I think I need to improve this question to help any others in the furture.
Here is the newest:
I need to make a square button like this:
My programme is a fullscreen programme that different device has different window's size.
So my square button should be can resizeable also beaucase I want to make a Reactive UI.
And now how can I make a square button?
Thank you.
It's perfectly fine to have pure UI logic like this live inside its code-behind. I'd even argue it's more efficient in most cases.
In your example, it's super easy to square your Rectangle with the following code
XAML
<Border x:Name="MyBorder"
Grid.Column="1"
Grid.Row="1"
SizeChanged="MyBorder_SizeChanged">
<Rectangle x:Name="MyRectangle"
Fill="LightBlue" />
</Border>
Code-behind
private void MyBorder_SizeChanged(object sender, SizeChangedEventArgs e)
{
if (MyBorder.ActualWidth > MyBorder.ActualHeight)
{
MyRectangle.Width = MyRectangle.Height = MyBorder.ActualHeight;
}
else if (MyBorder.ActualWidth < MyBorder.ActualHeight)
{
MyRectangle.Height = MyRectangle.Height = MyBorder.ActualWidth;
}
}
But can we improve this? Since you want a square Button, it makes most sense to create a SquareButton and insert it straight into your Grid.
So the XAML can be simplified to a much more readable version below
<local:SquareButton Grid.Column="1" Grid.Row="1" />
Then you just need to implement the custom control like the following
SquareButton class
[TemplatePart(Name = PART_Root, Type = typeof(Border))]
[TemplatePart(Name = PART_ContentHost, Type = typeof(Border))]
public sealed class SquareButton : Button
{
private const string PART_Root = "Root";
private const string PART_ContentHost = "ContentHost";
public SquareButton()
{
DefaultStyleKey = typeof(SquareButton);
}
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
var root = (Border)GetTemplateChild(PART_Root);
var contentHost = (Border)GetTemplateChild(PART_ContentHost);
root.SizeChanged += (s, e) =>
{
if (root.ActualWidth > root.ActualHeight)
{
contentHost.Width = contentHost.Height = root.ActualHeight;
}
else if (root.ActualWidth < root.ActualHeight)
{
contentHost.Height = contentHost.Height = root.ActualWidth;
}
};
}
}
SquareButton Style inside Themes/Generic.xaml
<Style TargetType="local:SquareButton">
<Setter Property="Background"
Value="{ThemeResource SystemControlBackgroundBaseLowBrush}" />
<Setter Property="Foreground"
Value="{ThemeResource SystemControlForegroundBaseHighBrush}" />
<Setter Property="BorderBrush"
Value="{ThemeResource SystemControlForegroundTransparentBrush}" />
<Setter Property="BorderThickness"
Value="{ThemeResource ButtonBorderThemeThickness}" />
<Setter Property="Padding"
Value="8,4,8,4" />
<Setter Property="HorizontalAlignment"
Value="Stretch" />
<Setter Property="VerticalAlignment"
Value="Stretch" />
<Setter Property="FontFamily"
Value="{ThemeResource ContentControlThemeFontFamily}" />
<Setter Property="FontWeight"
Value="Normal" />
<Setter Property="FontSize"
Value="{ThemeResource ControlContentThemeFontSize}" />
<Setter Property="UseSystemFocusVisuals"
Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:SquareButton">
<Border x:Name="Root">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<Storyboard>
<PointerUpThemeAnimation Storyboard.TargetName="ContentHost" />
</Storyboard>
</VisualState>
<VisualState x:Name="PointerOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SystemControlHighlightBaseMediumLowBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SystemControlHighlightBaseHighBrush}" />
</ObjectAnimationUsingKeyFrames>
<PointerUpThemeAnimation Storyboard.TargetName="ContentHost" />
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentHost"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SystemControlBackgroundBaseMediumLowBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SystemControlHighlightTransparentBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SystemControlHighlightBaseHighBrush}" />
</ObjectAnimationUsingKeyFrames>
<PointerDownThemeAnimation Storyboard.TargetName="ContentHost" />
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentHost"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SystemControlBackgroundBaseLowBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SystemControlDisabledBaseMediumLowBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SystemControlDisabledTransparentBrush}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border x:Name="ContentHost" Background="{TemplateBinding Background}">
<ContentPresenter x:Name="ContentPresenter"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Content="{TemplateBinding Content}"
ContentTransitions="{TemplateBinding ContentTransitions}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Padding="{TemplateBinding Padding}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
AutomationProperties.AccessibilityView="Raw" />
</Border>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Hope this helps!
Use the Rectangle.Stretch property:
<Rectangle Fill="Red" Stretch="Uniform"></Rectangle>
I think this answers the actual question of creating a rectangle where width and height are the same and the rectangle is stretched to the available space.
In terms of binding, a MultiBinding on both Width and Height with an IMultiValueConverter implementation that returns the minimum of all input values might work. However, it's only needed for controls that don't provide automated stretching.
You can use attached properties to set the same width/height for a given limit:
public static class SquareSize
{
public static double GetWidthLimit(DependencyObject obj)
{
return (double)obj.GetValue(WidthLimitProperty);
}
public static void SetWidthLimit(DependencyObject obj, double value)
{
obj.SetValue(WidthLimitProperty, value);
}
public static readonly DependencyProperty WidthLimitProperty = DependencyProperty.RegisterAttached(
"WidthLimit", typeof(double), typeof(SquareSize),
new FrameworkPropertyMetadata(double.PositiveInfinity, new PropertyChangedCallback(OnWidthLimitChanged)));
private static void OnWidthLimitChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
UpdateSize(d, (double)e.NewValue, GetHeightLimit(d));
}
public static double GetHeightLimit(DependencyObject obj)
{
return (double)obj.GetValue(HeightLimitProperty);
}
public static void SetHeightLimit(DependencyObject obj, double value)
{
obj.SetValue(HeightLimitProperty, value);
}
public static readonly DependencyProperty HeightLimitProperty = DependencyProperty.RegisterAttached(
"HeightLimit", typeof(double), typeof(SquareSize),
new FrameworkPropertyMetadata(double.PositiveInfinity, new PropertyChangedCallback(OnHeightLimitChanged)));
private static void OnHeightLimitChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
UpdateSize(d, GetWidthLimit(d), (double)e.NewValue);
}
private static void UpdateSize(DependencyObject d, double widthLimit, double heightLimit)
{
double resultSize = Math.Min(widthLimit, heightLimit);
d.SetCurrentValue(FrameworkElement.WidthProperty, resultSize);
d.SetCurrentValue(FrameworkElement.HeightProperty, resultSize);
}
}
Use with appropriate xmlns namespace
<Border x:Name="border" Grid.Column="1" Grid.Row="1">
<Rectangle
Fill="Red"
local:SquareSize.WidthLimit="{Binding ElementName=border,Path=ActualWidth}"
local:SquareSize.HeightLimit="{Binding ElementName=border,Path=ActualHeight}"/>
</Border>
A solution involving a custom control as wrapper for square-spaced content:
public class SquareContentControl : ContentControl
{
protected override Size ArrangeOverride(Size arrangeBounds)
{
var sizeLimit = Math.Min(arrangeBounds.Width, arrangeBounds.Height);
if (VisualChildrenCount > 0)
{
var child = GetVisualChild(0) as UIElement;
if (child != null)
{
child.Arrange(new Rect(new Point((arrangeBounds.Width - sizeLimit) / 2, (arrangeBounds.Height - sizeLimit) / 2), new Size(sizeLimit, sizeLimit)));
return arrangeBounds;
}
}
return base.ArrangeOverride(arrangeBounds);
}
protected override Size MeasureOverride(Size constraint)
{
var sizeLimit = Math.Min(constraint.Width, constraint.Height);
if (VisualChildrenCount > 0)
{
var child = GetVisualChild(0) as UIElement;
if (child != null)
{
child.Measure(new Size(sizeLimit, sizeLimit));
return child.DesiredSize;
}
}
return base.MeasureOverride(constraint);
}
}
Usage:
<Border x:Name="border" Grid.Column="1" Grid.Row="1">
<local:SquareContentControl>
<Rectangle Fill="Red"/>
</local:SquareContentControl>
</Border>
EDIT 2017/8/17 only works on WPF, not UWP.
Using Minimum Converter:
public class MinConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
double result = double.NaN;
if (values != null)
{
try
{
result = values.Cast<double>().Aggregate(double.PositiveInfinity, (a, b) => Math.Min(a, b));
}
catch (Exception)
{
result = double.NaN;
}
}
return result;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
Then in your xaml set the Rectangle Height to match parent's Border Min(ActualHeight, ActualWidth). And the Rectangle Width can just bind to Rectangle's ActualHeight
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="0.1*"></RowDefinition>
<RowDefinition Height="0.8*"></RowDefinition>
<RowDefinition Height="0.1*"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.1*"></ColumnDefinition>
<ColumnDefinition Width="0.8*"></ColumnDefinition>
<ColumnDefinition Width="0.1*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Border x:Name="Bd" Grid.Column="1" Grid.Row="1">
<Rectangle x:Name="R"
Width="{Binding Path=ActualHeight, Mode=OneWay, RelativeSource={RelativeSource Self}}">
<Rectangle.Height>
<MultiBinding Converter="converter:MinConverter">
<Binding ElementName="Bd" Path="ActualHeight"/>
<Binding ElementName="Bd" Path="ActualWidth"/>
</MultiBinding>
</Rectangle.Height>
</Rectangle>
</Border>
</Grid>

Text Box sometimes cursor is missing

I have created a custom water mark text box which is extended from text box. control template for the same is shown below.
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:WaterMarkTextBox}">
<ControlTemplate.Resources>
<Storyboard x:Key="Storyboard1">
<ThicknessAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Margin)"
Storyboard.TargetName="PART_FieldTextBlock">
<SplineThicknessKeyFrame KeyTime="0:0:0.15"
Value="0,0,10,0" />
</ThicknessAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="Storyboard2">
<ThicknessAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Margin)"
Storyboard.TargetName="PART_FieldTextBlock">
<SplineThicknessKeyFrame KeyTime="0:0:0.25"
Value="0,0,-500,0" />
</ThicknessAnimationUsingKeyFrames>
</Storyboard>
</ControlTemplate.Resources>
<Grid x:Name="PART_GridControl"
ClipToBounds="True"
Height="{TemplateBinding Height}"
Width="{TemplateBinding Width}">
<TextBlock x:Name="PART_PlaceHolderTextBlock"
Style="{StaticResource SWMLightTextBlockStyle}"
Foreground="#BDBBBB"
FontSize="{StaticResource SmallFontSize}"
Text="{TemplateBinding PlaceHolderText}"
VerticalAlignment="Center"
Margin="20,0,10,0" />
<Border Name="border"
CornerRadius="0"
Padding="2"
BorderThickness="1"
BorderBrush="DeepSkyBlue">
<ScrollViewer x:Name="PART_ContentHost"/>
</Border>
<TextBlock x:Name="PART_FieldTextBlock"
HorizontalAlignment="Right"
Foreground="#BDBBBB"
Margin="0,0,-500,0"
Style="{StaticResource SWMLightTextBlockStyle}"
FontSize="{StaticResource SmallFontSize}"
TextWrapping="Wrap"
Text="{TemplateBinding FieldText}"
VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
but while typing the textbox enters to a condition where it is having no cursor but we can type into it occurs with a probability of 1/2 chars.I wonder how it happens. Anyone is having idea how it is happening?
Two things You can do. First One is Overriding SystemParameters Properties Using reflection Like this
void LocallyDisableMouseVanish()
{
foreach (var field in typeof(SystemParameters).GetFields(BindingFlags.NonPublic|BindingFlags.Static))
if (field.Name.Contains("mouseVanish"))
field.SetValue(null, false);
}
Call this method On Focus Of your Control.
If this is Not working means You can Try something Like this Override the style of the Caret Like this
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:WaterMarkTextBox}">
<ControlTemplate.Resources>
<Storyboard x:Key="Storyboard1">
<ThicknessAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Margin)"
Storyboard.TargetName="PART_FieldTextBlock">
<SplineThicknessKeyFrame KeyTime="0:0:0.15"
Value="0,0,10,0" />
</ThicknessAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="Storyboard2">
<ThicknessAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Margin)"
Storyboard.TargetName="PART_FieldTextBlock">
<SplineThicknessKeyFrame KeyTime="0:0:0.25"
Value="0,0,-500,0" />
</ThicknessAnimationUsingKeyFrames>
</Storyboard>
</ControlTemplate.Resources>
<Grid x:Name="PART_GridControl"
ClipToBounds="True"
Height="{TemplateBinding Height}"
Width="{TemplateBinding Width}">
<TextBlock x:Name="PART_PlaceHolderTextBlock"
Style="{StaticResource SWMLightTextBlockStyle}"
Foreground="#BDBBBB"
FontSize="{StaticResource SmallFontSize}"
Text="{TemplateBinding PlaceHolderText}"
VerticalAlignment="Center"
Margin="20,0,10,0" />
<Border Name="border"
CornerRadius="0"
Padding="2"
BorderThickness="1"
BorderBrush="DeepSkyBlue">
<ScrollViewer x:Name="PART_ContentHost" />
</Border>
<TextBlock x:Name="PART_FieldTextBlock"
HorizontalAlignment="Right"
Foreground="#BDBBBB"
Margin="0,0,-500,0"
Style="{StaticResource SWMLightTextBlockStyle}"
FontSize="{StaticResource SmallFontSize}"
TextWrapping="Wrap"
Text="{TemplateBinding FieldText}"
VerticalAlignment="Center" />
<Canvas>
<Border x:Name="PART_Caret"
Visibility="Collapsed"
Canvas.Left="0"
Canvas.Top="0"
Width="5"
Height="25"
Background="Black"
BorderThickness="1">
<Border.Triggers>
<EventTrigger RoutedEvent="Border.Loaded">
<BeginStoryboard>
<Storyboard x:Name="CaretStoryBoard"
RepeatBehavior="Forever">
<ColorAnimationUsingKeyFrames Storyboard.TargetProperty="Background.Color"
Duration="0:0:0:1"
FillBehavior="HoldEnd">
<ColorAnimationUsingKeyFrames.KeyFrames>
<DiscreteColorKeyFrame KeyTime="0:0:0.750"
Value="Transparent" />
<DiscreteColorKeyFrame KeyTime="0:0:0.000"
Value="Black" />
</ColorAnimationUsingKeyFrames.KeyFrames>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Border.Triggers>
</Border>
</Canvas>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="CaretBrush "
Value="Transparent" />
And in your control code Add this
public override void OnApplyTemplate()
{
this.border = this.GetTemplateChild("PART_Caret") as Border;
base.OnApplyTemplate();
}
And add this Method
private void MoveCustomCaret()
{
var caretLocation = this.GetRectFromCharacterIndex(this.CaretIndex).Location;
if (!double.IsInfinity(caretLocation.X))
{
Canvas.SetLeft(border, caretLocation.X);
}
if (!double.IsInfinity(caretLocation.Y))
{
Canvas.SetTop(border, caretLocation.Y);
}
}
And Finally Call This method and set the visibility of the border
private void SWMTextBox_GotFocus(object sender, RoutedEventArgs e)
{
MoveCustomCaret();
border.Visibility = Visibility.Visible;
}
also in TextChangedEvent
private void CustomTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
MoveCustomCaret();
}
And Hid the Visibility in Lost_Focus_Event
private void SWMTextBox_LostFocus(object sender, RoutedEventArgs e)
{
border.Visibility = Visibility.Hidden;
}

InputDialog positioning issue

In a windows store app, i have the following page
<common:LayoutAwarePage
x:Class="Gapp_metro.Pages.DocumentsPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Gapp_metro.Pages"
xmlns:common="using:Gapp_metro.Common"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">
<Grid Style="{StaticResource RootGridStyle}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<Grid Style="{StaticResource HeaderGridStyle}" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button Click="GoBack" IsEnabled="{Binding Frame.CanGoBack}" Style="{StaticResource BackButtonStyle}" />
<TextBlock x:Name="pageTitle" Grid.Column="1" Text="{Binding Title}" Style="{StaticResource PageHeaderTextStyle}" />
</Grid>
<Grid Grid.Row="1" Style="{StaticResource ContentGridStyle}" VerticalAlignment="Center">
<GridView x:Name="gridView" Grid.Row="1" ItemsSource="{Binding Tiles}" Style="{StaticResource GridViewStyle}" ItemClick="OnItemClick" />
<ListView x:Name="listView" Grid.Row="1" ItemsSource="{Binding Tiles}" Style="{StaticResource ListViewStyle}" ItemClick="OnItemClick"
Visibility="Collapsed" />
<ProgressRing x:Name="ProgressR" Grid.Row="1" IsActive="{Binding IsLoading}" />
</Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="ApplicationViewStates">
<VisualState x:Name="FullScreenLandscape" />
<VisualState x:Name="Filled"/>
<VisualState x:Name="FullScreenPortrait" />
<VisualState x:Name="Snapped">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="backButton" Storyboard.TargetProperty="Style">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource SnappedBackButtonStyle}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="pageTitle" Storyboard.TargetProperty="Style">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource SnappedPageHeaderTextStyle}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="gridView" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="listView" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="Visible" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
<Page.BottomAppBar>
<AppBar x:Name="appBar" Style="{StaticResource AppBarStyle}">
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
<Button Click="OnAddButtonClick" Style="{StaticResource AddAppBarButtonStyle}" />
<Button Click="OnUploadButtonClick" Style="{StaticResource UploadAppBarButtonStyle}" />
<Button Click="OnPhotoButtonClick" Style="{StaticResource PhotoAppBarButtonStyle}" />
</StackPanel>
</AppBar>
</Page.BottomAppBar>
and in my code behind i have this function for the "Click="OnAddButtonClick""
private async void OnAddButtonClick(object sender, RoutedEventArgs e)
{
var dialog = new InputDialog();
dialog.BackgroundStripeBrush = new SolidColorBrush(Color.FromArgb(255, 149, 191, 0));
dialog.Background = new SolidColorBrush(Color.FromArgb(255, 149, 191, 0));
dialog.BorderBrush = new SolidColorBrush(Color.FromArgb(255, 149, 191, 0));
Style buttonStyle = new Style() { TargetType = typeof(Button) };
buttonStyle.Setters.Add(new Setter(BackgroundProperty, new SolidColorBrush(Colors.Transparent)));
dialog.ButtonStyle = buttonStyle;
var result = await dialog.ShowAsync(App.Current.Resources["createFolder"] as String, App.Current.Resources["newFolderName"] as String, App.Current.Resources["create"] as String, App.Current.Resources["close"] as String);
dialog.VerticalAlignment = VerticalAlignment.Top;
dialog.Margin = new Thickness(0, 0, 0, 0);
....
but when i press the add button, the input dialog always appears in the center of screen, even tho i tried to add a vertical alignment and margins.
pretty sure im missing something silly
how do i make it appear on the top ?
You should set VerticalAlignment and Margin before calling ShowAsync.

Visual States and a custom dependency property (MVVM)

I'm stuck trying to add a dependency property to a button. I have several buttons located in my header view and clicking on them changes the content in the ContentControl between different views. All this works great. I want the button that was clicked have a different forecolor than the others and it looks like I need to add a dependency property. I think I have all the pieces in place but can't figure out how to get them all to work together.
I have a string property named ViewState in my viewmodel which changes based upon the button being clicked. The property is changing and I'm calling RaisePropertyChanged when it happens. What do I need to do to bind the additional dependency property? I'm transitioning from the WinForm world and trying to mentally piece it all together but struggling a bit.
Here's what I have so far:
<Style TargetType="{x:Type Button}" x:Key="LocalButtonTemplate">
<Setter Property="Foreground" Value="White" />
<Setter Property="Background" Value="{x:Null}" />
<Setter Property="FontFamily" Value="Segoe UI" />
<Setter Property="FontSize" Value="18" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="outerBorder" Background="{TemplateBinding Background}" Margin="4">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="ViewState">
<VisualState x:Name="Dashboard">
<Storyboard>
<ColorAnimation Duration="0:0:0.1" To="Yellow"
Storyboard.TargetProperty="(TextElement.Foreground).(SolidColorBrush.Color)"
Storyboard.TargetName="contentPresenter"/>
</Storyboard>
</VisualState>
<VisualState x:Name="AccountTables">
<Storyboard>
<ColorAnimation Duration="0:0:0.1" To="Red"
Storyboard.TargetProperty="(TextElement.Foreground).(SolidColorBrush.Color)"
Storyboard.TargetName="contentPresenter"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Normal">
<Storyboard>
<ColorAnimation Duration="0:0:0.1" To="Purple"
Storyboard.TargetProperty="(TextElement.Foreground).(SolidColorBrush.Color)"
Storyboard.TargetName="contentPresenter"/>
</Storyboard>
</VisualState>
<VisualState x:Name="MouseOver">
<Storyboard>
<ColorAnimation Duration="0:0:0.1" To="#35A84D"
Storyboard.TargetProperty="(TextElement.Foreground).(SolidColorBrush.Color)"
Storyboard.TargetName="contentPresenter"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid>
<Border x:Name="Background" BorderBrush="Transparent">
<Grid>
<ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Margin="4,5,4,4"/>
</Grid>
</Border>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
My buttons:
<dxwuii:SplitPanel Margin="0,10,10,10" HorizontalAlignment="Right" Grid.Column="2" ItemSpacing="0" Orientation="Horizontal" ItemSizeMode="AutoSize" >
<Button Command="{Binding SendViewModelNameCommand, Mode=OneTime}" CommandParameter="AccountTablesViewModel" Style="{StaticResource LocalButtonTemplate}">Express Tables</Button>
<Button Command="{Binding SendViewModelNameCommand, Mode=OneTime}" CommandParameter="MappingViewModel" Style="{StaticResource LocalButtonTemplate}">Item Mapping</Button>
<Button Command="{Binding SendViewModelNameCommand, Mode=OneTime}" CommandParameter="ReportsViewModel" Style="{StaticResource LocalButtonTemplate}">Reports</Button>
<Button Command="{Binding SendViewModelNameCommand, Mode=OneTime}" CommandParameter="PostBalancesViewModel" Style="{StaticResource LocalButtonTemplate}">Post Balances</Button>
</dxwuii:SplitPanel>
Dependency Property Class:
namespace MyAppName.Model
{
public class StateManager : DependencyObject
{
public static string GetVisualStateProperty(DependencyObject obj)
{
return (string)obj.GetValue(VisualStatePropertyProperty);
}
public static void SetVisualStateProperty(DependencyObject obj, string value)
{
obj.SetValue(VisualStatePropertyProperty, value);
}
public static readonly DependencyProperty VisualStatePropertyProperty =
DependencyProperty.RegisterAttached(
"VisualStateProperty",
typeof(string),
typeof(StateManager),
new PropertyMetadata((dependencyObject, args) =>
{
var frameworkElement = dependencyObject as FrameworkElement;
if (frameworkElement == null)
return;
VisualStateManager.GoToState(frameworkElement, (string)args.NewValue, true);
}));
}
}
Set Tag and Attached property on your each button as below. Tag value will be the VisualState value to which button should go on click.
<Button Tag="AcountTables" local:StateManager.VisualStateProperty="{Binding YOURVIEWMODELPROPERTY}" Command="{Binding SendViewModelNameCommand, Mode=OneTime}" CommandParameter="AccountTablesViewModel" Style="{StaticResource LocalButtonTemplate}">Express Tables</Button>
Update your AttachedProperty like:
public static readonly DependencyProperty VisualStatePropertyProperty =
DependencyProperty.RegisterAttached(
"VisualStateProperty",
typeof(string),
typeof(StateManager),
new PropertyMetadata((dependencyObject, args) =>
{
var frameworkElement = dependencyObject as FrameworkElement;
if (frameworkElement == null)
return;
if (args.NewValue == frameworkElement.Tag.ToString())
{
VisualStateManager.GoToState(frameworkElement, (string)args.NewValue, true);
}
else
{
VisualStateManager.GoToState(frameworkElement, "Normal", true);
}
}));

Categories