I just wanted to start off saying I've seen similar posts with the same issue but they give a solution not suitable to my scenario. I'm making a SplitView Control as shown below. Problem is the Control has 3 areas where users can place whatever controls they want, but those controls can't be named via this error:
Cannot set Name attribute value 'Item1' on element 'ListViewItem'. 'ListViewItem' is under the scope of element 'SplitView', which already had a name registered when it was defined in another scope.
How can I fix this? I don't want the implementation of this control to have to always have to add some code to get around this error. Could I add a 3 template areas in this control so the user can make a their own template with content they want inside each area. How would I do this? I'm open to other ideas.
Markup
<UserControl x:Name="ThisControl" x:Class="ns.SplitView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" DataContext="{Binding RelativeSource={RelativeSource Self}}"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Button Margin="10" Grid.Row="0" Grid.Column="0" x:Name="OpenPaneButton" Width="50" Height="50" Click="OpenPaneButton_Click" Background="{x:Null}" BorderBrush="{x:Null}" Focusable="False" >
<Viewbox>
<Canvas Width="300" Height="210">
<Path StrokeThickness="1" StrokeDashArray="" StrokeDashCap="Flat" StrokeDashOffset="0" StrokeStartLineCap="Flat" StrokeEndLineCap="Flat" StrokeLineJoin="Miter" StrokeMiterLimit="10" Stroke="{Binding HamburgerButtonColor, ElementName=ThisControl}" Fill="{Binding HamburgerButtonColor, ElementName=ThisControl}">
<Path.Data>
<RectangleGeometry Rect="0,0,300,50" RadiusX="25" RadiusY="25" />
</Path.Data>
</Path>
<Path StrokeThickness="1" StrokeDashArray="" StrokeDashCap="Flat" StrokeDashOffset="0" StrokeStartLineCap="Flat" StrokeEndLineCap="Flat" StrokeLineJoin="Miter" StrokeMiterLimit="10" Stroke="{Binding HamburgerButtonColor, ElementName=ThisControl}" Fill="{Binding HamburgerButtonColor, ElementName=ThisControl}">
<Path.Data>
<RectangleGeometry Rect="0,80,300,50" RadiusX="25" RadiusY="25" />
</Path.Data>
</Path>
<Path StrokeThickness="1" StrokeDashArray="" StrokeDashCap="Flat" StrokeDashOffset="0" StrokeStartLineCap="Flat" StrokeEndLineCap="Flat" StrokeLineJoin="Miter" StrokeMiterLimit="10" Stroke="{Binding HamburgerButtonColor, ElementName=ThisControl}" Fill="{Binding HamburgerButtonColor, ElementName=ThisControl}">
<Path.Data>
<RectangleGeometry Rect="0,160,300,50" RadiusX="25" RadiusY="25" />
</Path.Data>
</Path>
</Canvas>
</Viewbox>
</Button>
<ContentPresenter x:Name="MainTitleContent" Panel.ZIndex="1" Content="{Binding TitleContent, ElementName=ThisControl}" Grid.Row="0" Grid.Column="1" Focusable="True"/>
<ContentPresenter x:Name="Pane" Panel.ZIndex="1" Grid.ColumnSpan="2" Grid.Column="0" Grid.Row="0" Grid.RowSpan="2" Width="0" HorizontalAlignment="Left" Content="{Binding PaneContent, ElementName=ThisControl}" LostFocus="Pane_LostFocus" LostMouseCapture="Pane_LostMouseCapture" LostKeyboardFocus="Pane_LostKeyboardFocus" LostTouchCapture="Pane_LostTouchCapture" LostStylusCapture="Pane_LostStylusCapture" Focusable="True"/>
<ContentPresenter x:Name="Content" Grid.ColumnSpan="2" Grid.Column="0" Grid.Row="1" Content="{Binding MainContent, ElementName=ThisControl}" Focusable="True"/>
</Grid>
</UserControl>
Code Behind
using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
namespace ns
{
public partial class SplitView
{
/// <summary>
/// A simple state to know if the pane is open
/// </summary>
public bool PaneIsOpen
{
get { return (bool)GetValue(PaneIsOpenProperty); }
set { SetValue(PaneIsOpenProperty, value); }
}
public static readonly DependencyProperty PaneIsOpenProperty = DependencyProperty.Register("PaneIsOpen", typeof(bool), typeof(SplitView));
public SolidColorBrush HamburgerButtonColor
{
get { return (SolidColorBrush)GetValue(HamburgerButtonColorProperty); }
set { SetValue(HamburgerButtonColorProperty, value); }
}
public static readonly DependencyProperty HamburgerButtonColorProperty = DependencyProperty.Register("HamburgerButtonColor", typeof(SolidColorBrush), typeof(SplitView), new UIPropertyMetadata(new SolidColorBrush(Colors.Black)));
public double PaneWidth
{
get { return (double)GetValue(PaneWidthProperty); }
set { SetValue(PaneWidthProperty, value); }
}
public static readonly DependencyProperty PaneWidthProperty = DependencyProperty.Register("PaneWidth", typeof(double), typeof(SplitView), new PropertyMetadata(null));
public object MainContent
{
get { return GetValue(MainContentProperty); }
set { SetValue(MainContentProperty, value); }
}
public static readonly DependencyProperty MainContentProperty = DependencyProperty.Register("MainContent", typeof(object), typeof(SplitView), new PropertyMetadata(null));
public object PaneContent
{
get { return GetValue(PaneContentProperty); }
set { SetValue(PaneContentProperty, value); }
}
public static readonly DependencyProperty PaneContentProperty = DependencyProperty.Register("PaneContent", typeof(object), typeof(SplitView), new PropertyMetadata(null));
public object TitleContent
{
get { return GetValue(TitleContentProperty); }
set { SetValue(TitleContentProperty, value); }
}
public static readonly DependencyProperty TitleContentProperty = DependencyProperty.Register("TitleContent", typeof(object), typeof(SplitView), new PropertyMetadata(null));
private readonly Duration PaneAnimationDuration = new Duration(new TimeSpan());
private DoubleAnimation ClosePaneAnimation => new DoubleAnimation {Duration = PaneAnimationDuration, To = 0, From = PaneWidth };
private DoubleAnimation OpenPaneAnimation => new DoubleAnimation {Duration = PaneAnimationDuration, To = PaneWidth, From = 0 };
public SplitView()
{
InitializeComponent();
}
private void OpenPaneButton_Click(object sender, RoutedEventArgs e)
{
PaneIsOpen = !PaneIsOpen;
//Debug.WriteLine($"pane is open: {PaneIsOpen}");
if (PaneIsOpen)
{
Pane.BeginAnimation(WidthProperty, OpenPaneAnimation);
Pane.Focus();
}
else
{
Pane.BeginAnimation(WidthProperty, ClosePaneAnimation);
}
}
private void Pane_LostFocus(object sender, RoutedEventArgs e)
{
PaneLostFocus();
e.Handled = true;
}
private void Pane_LostMouseCapture(object sender, MouseEventArgs e)
{
PaneLostFocus();
e.Handled = true;
}
private void PaneLostFocus()
{
if (PaneIsOpen)
{
PaneIsOpen = false;
Pane.BeginAnimation(WidthProperty, ClosePaneAnimation);
}
}
private void Pane_LostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
PaneLostFocus();
e.Handled = true;
}
private void Pane_LostTouchCapture(object sender, TouchEventArgs e)
{
PaneLostFocus();
e.Handled = true;
}
private void Pane_LostStylusCapture(object sender, StylusEventArgs e)
{
PaneLostFocus();
e.Handled = true;
}
}
}
Implementation
<customControls:SplitView x:Name="SplitView" PaneWidth="250" HamburgerButtonColor="{StaticResource AccentColorBrush2}">
<customControls:SplitView.MainContent>
<Grid>
</Grid>
</customControls:SplitView.MainContent>
<customControls:SplitView.PaneContent>
<Grid Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Text="Navigation" Style="{StaticResource Header1}" Margin="10,5,5,5"/>
<!-- I can't name controls in these content areas -->
<ListView Grid.Row="1" BorderThickness="0" SelectionChanged="PaneItemsListView_SelectionChanged">
<ListViewItem x:Name="Item1" Style="{StaticResource SplitViewItemsStyle}" ">
<TextBlock Text="Project Explorer" Margin="20,5,10,5"/>
</ListViewItem>
<ListViewItem Style="{StaticResource SplitViewItemsStyle}" Tag="FieldServicesItem">
<TextBlock Text="Field Services" Margin="20,5,10,5"/>
</ListViewItem>
<ListViewItem Style="{StaticResource SplitViewItemsStyle}" Tag="ReportManagerItem">
<TextBlock Text="Report Manager" Margin="20,5,10,5"/>
</ListViewItem>
</ListView>
</Grid>
</customControls:SplitView.PaneContent>
<customControls:SplitView.TitleContent>
<Grid>
<TextBlock HorizontalAlignment="Center" Text="Current View" VerticalAlignment="Center" Style="{StaticResource Header1}"/>
</Grid>
</customControls:SplitView.TitleContent>
</customControls:SplitView>
Related
When i try to set VirtualizationMode on my ListView to Recycling I get the error from the title:
Cannot change the VirtualizationMode attached property on an
ItemsControl after Measure is called on the ItemsHost panel.
I am trying to set the attached property programmatically but when I try to define the VirtualizationMode in XAML designer throws the same error from the title. Anyone had similar problems like this?
My view in XAML is:
<Window x:Class="FinalVirtualizationApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:FinalVirtualizationApp"
mc:Ignorable="d"
Title="MainWindow" Height="900" Width="800"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
TextElement.FontWeight="Regular"
TextElement.FontSize="13"
TextOptions.TextFormattingMode="Ideal"
TextOptions.TextRenderingMode="Auto"
Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{DynamicResource MaterialDesignFont}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<GroupBox Grid.Row="0" Header="UI virtualization options">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<CheckBox Content="UI virtualization" VerticalAlignment="Center" IsChecked="{Binding IsUIVirtualization}"/>
<Grid Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Label Content="Container Recycling:" VerticalAlignment="Center"/>
<ComboBox Grid.Column="1" VerticalAlignment="Center" SelectedValue="{Binding ContainerRecyclingType}" SelectedValuePath="Content">
<ComboBoxItem>Recycling</ComboBoxItem>
<ComboBoxItem>Standard</ComboBoxItem>
</ComboBox>
</Grid>
<CheckBox Content="Deferred scrolling" Grid.Row="1" VerticalAlignment="Center" IsChecked="{Binding IsDeferredScrolling}">
</CheckBox>
<Grid Grid.Row="1" Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="74*"/>
<ColumnDefinition Width="253*"/>
</Grid.ColumnDefinitions>
<Label Content="Scroll unit" VerticalAlignment="Center" Margin="0,0,0,1"/>
<ComboBox Grid.Column="1" VerticalAlignment="Center" SelectedValue="{Binding ScrollUnitType}" SelectedValuePath="Content" Grid.ColumnSpan="2" Margin="0,2,0,3">
<ComboBoxItem>Item</ComboBoxItem>
<ComboBoxItem>Pixel</ComboBoxItem>
</ComboBox>
</Grid>
</Grid>
</GroupBox>
<GroupBox Grid.Row="1" Header="Data virtualization">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<GroupBox Header="ItemsProvider">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal">
<Label Content="Number of Items: "/>
<TextBox Width="60" Text="{Binding NumberOfItems}"/>
</StackPanel>
<StackPanel Grid.Column="1" Orientation="Horizontal">
<Label Content="Fetch delay(ms): "/>
<TextBox Width="60" Text="{Binding FetchDelay}"/>
</StackPanel>
</Grid>
</GroupBox>
<GroupBox Grid.Row="1" Header="Collection">
<StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,2,0,0">
<TextBlock Text="Type:" Margin="5" TextAlignment="Right" VerticalAlignment="Center"/>
<RadioButton x:Name="rbNormal" GroupName="rbGroup" Margin="5" Content="List(T)" VerticalAlignment="Center" Command="{Binding CollectionTypeChangeCommand}" CommandParameter="List"/>
<RadioButton x:Name="rbVirtualizing" GroupName="rbGroup" Margin="5" Content="VirtualizingList(T)" VerticalAlignment="Center" Command="{Binding CollectionTypeChangeCommand}" CommandParameter="VirtualizingList"/>
<RadioButton x:Name="rbAsync" GroupName="rbGroup" Margin="5" Content="AsyncVirtualizingList(T)" VerticalAlignment="Center" Command="{Binding CollectionTypeChangeCommand}" CommandParameter="AsyncVirtualizingList"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,2,0,0">
<TextBlock Text="Page size:" Margin="5" TextAlignment="Right" VerticalAlignment="Center"/>
<TextBox x:Name="tbPageSize" Margin="5" Text="{Binding PageSize}" Width="60" VerticalAlignment="Center"/>
<TextBlock Text="Page timeout (s):" Margin="5" TextAlignment="Right" VerticalAlignment="Center"/>
<TextBox x:Name="tbPageTimeout" Margin="5" Text="{Binding PageTimeout}" Width="60" VerticalAlignment="Center"/>
</StackPanel>
</StackPanel>
</GroupBox>
</Grid>
</GroupBox>
<StackPanel Orientation="Horizontal" Grid.Row="2">
<TextBlock Text="Memory Usage:" Margin="5" VerticalAlignment="Center"/>
<TextBlock x:Name="tbMemory" Margin="5" Width="80" Text="{Binding MemoryUsage}" VerticalAlignment="Center"/>
<Button Content="Refresh" Margin="5" Width="100" VerticalAlignment="Center" Command="{Binding RefreshCommand}"/>
</StackPanel>
<ListView Grid.Row="3" Name="lvItems">
<ListView.ItemTemplate>
<DataTemplate>
<Expander Header="{Binding DeviceName}">
<StackPanel>
</StackPanel>
</Expander>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Window>
And i try to set the VirtualizationMode here:
public void SetUIVirtualizationOptions()
{
listView.SetValue(VirtualizingStackPanel.IsVirtualizingProperty, IsUIVirtualization);
listView.SetValue(ScrollViewer.IsDeferredScrollingEnabledProperty, IsDeferredScrolling);
if(ContainerRecyclingType == "Recycling")
listView.SetValue(VirtualizingStackPanel.VirtualizationModeProperty, VirtualizationMode.Recycling);
else
listView.SetValue(VirtualizingStackPanel.VirtualizationModeProperty, VirtualizationMode.Standard);
if (ScrollUnitType == "Item")
listView.SetValue(VirtualizingPanel.ScrollUnitProperty, ScrollUnit.Item);
else
listView.SetValue(VirtualizingPanel.ScrollUnitProperty, ScrollUnit.Pixel);
}
Edit: My Window code behind where i pass the listview to viewmodel is:
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainWindowViewModel(lvItems);
}
}
And the viewmodel part of the code (minus getters and setters for less space taken):
public class MainWindowViewModel : BindableBase
{
#region private fields
private ListView listView;
private bool isUIVirtualization;
private bool isDeferredScrolling;
private string containerRecyclingType;
private string scrollUnitType;
private int numberOfItems;
private int fetchDelay;
private string collectionType;
private int pageSize;
private int pageTimeout;
private string memoryUsage;
private DemoItemProvider itemsProvider;
#endregion
#region commands
public RelayCommand<string> CollectionTypeChangeCommand { get; set; }
public RelayCommand RefreshCommand { get; set; }
public RelayCommand<string> ContainerRecyclingTypeChangeCommand { get; set; }
public RelayCommand<string> ScrollUnitTypeChangeCommand { get; set; }
#endregion
public MainWindowViewModel(ListView lvItems)
{
this.listView = lvItems;
PageSize = 100;
PageTimeout = 30;
NumberOfItems = 1000000;
FetchDelay = 1000;
CollectionTypeChangeCommand = new RelayCommand<string>(CollectionTypeChangeFunc);
RefreshCommand = new RelayCommand(RefreshFunc);
ContainerRecyclingTypeChangeCommand = new RelayCommand<string>(ContainerRecyclingTypeChangeFunc);
ScrollUnitTypeChangeCommand = new RelayCommand<string>(ScrollUnitTypeChangeFunc);
// use a timer to periodically update the memory usage
DispatcherTimer timer = new DispatcherTimer();
timer.Interval = new TimeSpan(0, 0, 1);
timer.Tick += timer_Tick;
timer.Start();
}
private void timer_Tick(object sender, EventArgs e)
{
MemoryUsage = string.Format("{0:0.00} MB", GC.GetTotalMemory(true) / 1024.0 / 1024.0);
}
#region command methods
public void CollectionTypeChangeFunc(string type)
{
CollectionType = type;
}
public void RefreshFunc()
{
SetUIVirtualizationOptions();
itemsProvider = new DemoItemProvider(NumberOfItems, FetchDelay);
if (collectionType == "List")
{
listView.ItemsSource = new List<DataItem>(itemsProvider.FetchRange(0, itemsProvider.FetchCount()));
}
else if (collectionType == "VirtualizingList")
{
listView.ItemsSource = new VirtualizingCollection<DataItem>(itemsProvider, pageSize);
}
else if (collectionType == "AsyncVirtualizingList")
{
listView.ItemsSource = new AsyncVirtualizingCollection<DataItem>(itemsProvider, pageSize, pageTimeout * 1000);
}
}
public void ContainerRecyclingTypeChangeFunc(string type)
{
ContainerRecyclingType = type;
}
public void ScrollUnitTypeChangeFunc(string type)
{
ScrollUnitType = type;
}
public void SetUIVirtualizationOptions()
{
listView.SetValue(VirtualizingStackPanel.IsVirtualizingProperty, IsUIVirtualization);
listView.SetValue(ScrollViewer.IsDeferredScrollingEnabledProperty, IsDeferredScrolling);
if(ContainerRecyclingType == "Recycling")
listView.SetValue(VirtualizingStackPanel.VirtualizationModeProperty, VirtualizationMode.Recycling);
else
listView.SetValue(VirtualizingStackPanel.VirtualizationModeProperty, VirtualizationMode.Standard);
if (ScrollUnitType == "Item")
listView.SetValue(VirtualizingPanel.ScrollUnitProperty, ScrollUnit.Item);
else
listView.SetValue(VirtualizingPanel.ScrollUnitProperty, ScrollUnit.Pixel);
}
#endregion
}
The code source for VirtualizingStackPanel indicates that this property can only be set before initialization of the panel:
/// <summary>
/// Attached property for use on the ItemsControl that is the host for the items being
/// presented by this panel. Use this property to modify the virtualization mode.
///
/// Note that this property can only be set before the panel has been initialized
/// </summary>
public static readonly DependencyProperty VirtualizationModeProperty =
DependencyProperty.RegisterAttached("VirtualizationMode", typeof(VirtualizationMode), typeof(VirtualizingStackPanel),
new FrameworkPropertyMetadata(VirtualizationMode.Standard));
You can indeed check this behavior later in the file:
//
// Set up info on first measure
//
if (HasMeasured)
{
VirtualizationMode oldVirtualizationMode = InRecyclingMode ? VirtualizationMode.Recycling : VirtualizationMode.Standard;
if (oldVirtualizationMode != virtualizationMode)
{
throw new InvalidOperationException(SR.Get(SRID.CantSwitchVirtualizationModePostMeasure));
}
}
else
{
HasMeasured = true;
}
and there is no way (according to source code) to set this HasMeasured property back to False unless you destroy and recreate the ListView.
It is so as the message says:
Your not allowed to _change the VirtualizationMode attached property
on an ItemsControl after Measure is called on the ItemsHost panel.
This means, that if ListView is already shown virtualizing mechanism being used and you are not allowed to change it.
If you set Visibility of ListView in XAML to Collapsed and set it only later to the Visible, then you can set the VirtualizationMode in code behind to wished value, but only once(so you can't change it after ListView become visible)!
private void Button_Click(object sender, RoutedEventArgs e)
{
listView.SetValue(VirtualizingStackPanel.VirtualizationModeProperty, VirtualizationMode.Recycling);
listView.Visibility = Visibility.Visible;
}
XAML:
<ListView x:Name="listView" ... Visibility="Collapsed">
I'm trying to fill my collection with color. I have a border control for displaying the color which is selected using PrepareContainerForItemOverride
method and i have a button control to popup the color in collection. Here is my code.
Picker.cs
public sealed class Picker : ItemsControl
{
private ObservableCollection<SolidColorBrush> _myColors;
public Picker()
{
this.DefaultStyleKey = typeof(Picker);
_myColors = new ObservableCollection<SolidColorBrush>()
{
new SolidColorBrush(Color.FromArgb(255,225,225,25)),
new SolidColorBrush(Color.FromArgb(255,225,25,25)),
new SolidColorBrush(Color.FromArgb(255,225,225,225)),
new SolidColorBrush(Color.FromArgb(255,25,225,25))
};
}
public ObservableCollection<SolidColorBrush> MyColors
{
get
{
return (ObservableCollection<SolidColorBrush>)GetValue(MyColorsProperty);
}
set { SetValue(MyColorsProperty, value); }
}
public static readonly DependencyProperty MyColorsProperty =
DependencyProperty.Register("MyColors",
typeof(ObservableCollection<SolidColorBrush>), typeof(Picker), new
PropertyMetadata(null));
public Popup popup;
protected override void OnApplyTemplate()
{
popup = GetTemplateChild("myPopup") as Popup;
var popupbutton = GetTemplateChild("btn1") as Button;
popupbutton.Click += Popupbutton_Click;
}
private void Popupbutton_Click(object sender, RoutedEventArgs e)
{
popup.IsOpen = popup.IsOpen ? false : true;
}
public bool openPopup
{
get { return (bool)GetValue(openPopupProperty); }
set { SetValue(openPopupProperty, value); }
}
public static readonly DependencyProperty openPopupProperty =
DependencyProperty.Register("openPopup", typeof(bool),
typeof(Picker), new PropertyMetadata(true));
public object Data { get; private set; }
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(String propname)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propname));
}
}
}
Generic.xaml
<Style TargetType="local:Picker" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:Picker">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel>
<Border Height="50" BorderBrush="Blue" BorderThickness="5">
<Border.Background>
<SolidColorBrush Color="{Binding Color}" />
</Border.Background>
</Border>
<Popup Name="myPopup" IsOpen="False" IsLightDismissEnabled="True">
<Grid Width="650" Height="300" Background="Red">
<ItemsControl ItemsSource="{TemplateBinding MyColors}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Border BorderThickness="6" BorderBrush="Black">
<Border.Background>
<SolidColorBrush Color="{Binding Color}" />
</Border.Background>
</Border>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Popup>
</StackPanel>
<Button Grid.Column="1" Name="btn1" Height="55" Content="Click me"/>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Here, I'm not able to popup the color in collection when the button is clicked and i need to display the selected color in the border contol using PrepareContainerForItemOverride method
The problem is you have bound wrong property to ItemsSource. And private field _myColors you have never used. I have edit your code. It works in my side.
Picker.cs
public Picker()
{
this.DefaultStyleKey = typeof(Picker);
MyColors = new ObservableCollection<SolidColorBrush>()
{
new SolidColorBrush(Color.FromArgb(255,225,225,25)),
new SolidColorBrush(Color.FromArgb(255,225,25,25)),
new SolidColorBrush(Color.FromArgb(255,225,225,225)),
new SolidColorBrush(Color.FromArgb(255,25,225,25))
};
}
public ObservableCollection<SolidColorBrush> MyColors
{
get
{
return (ObservableCollection<SolidColorBrush>)GetValue(MyColorsProperty);
}
set { SetValue(MyColorsProperty, value); }
}
public static readonly DependencyProperty MyColorsProperty =
DependencyProperty.Register("MyColors",
typeof(ObservableCollection<SolidColorBrush>), typeof(Picker), new
PropertyMetadata(null));
Generic.xaml
<Style TargetType="local:Picker" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:Picker">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel>
<Border Height="50" BorderBrush="Blue" BorderThickness="5">
<Border.Background>
<SolidColorBrush Color="{Binding Color}" />
</Border.Background>
</Border>
<Popup Name="myPopup" IsOpen="False" IsLightDismissEnabled="True">
<Grid Width="650" Height="300" >
<ItemsControl ItemsSource="{TemplateBinding MyColors}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Border BorderThickness="15" BorderBrush="{Binding}">
</Border>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Popup>
</StackPanel>
<Button Grid.Column="1" Name="btn1" Height="55" Content="Click me"/>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I am Working on Windows phone 8.1.I Making Simple ListView Demo Which is Contain two Image And Two TextBlock.
<ListView x:Name="lst1" Grid.ColumnSpan="2" >
<ListView.ItemTemplate>
<DataTemplate >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Image x:Name="imgSender" Source="Assets/button_register.png" Stretch="None" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="8,15,8,8" />
<TextBlock Text="{Binding Sender}" FontSize="18" Foreground="Black" FontWeight="Bold" HorizontalAlignment="Center" Margin="0,12,0,0"/>
<Image x:Name="imgReceiver" Source="Assets/button_register.png" Grid.Row="1" Stretch="None" VerticalAlignment="Top" Margin="4,0" />
<TextBlock Text="{Binding Receiver}" FontSize="18" Foreground="Black" FontWeight="Bold" HorizontalAlignment="Center" Grid.Row="1" VerticalAlignment="Top"/>
<Image Source="Assets/scroll_line_addcategory.png" Grid.Row="2" Stretch="None" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="4,8,4,0" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
And My Problem is That I Want to Set the Visibility of 'imgSender' at Runtime in Xaml.cs File.
Is Anybuddy Have Any Idea For Access UI Control Contain by Data Template.
<ListView x:Name="lst1" Grid.ColumnSpan="2" >
<ListView.ItemTemplate>
<DataTemplate >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Image Visibility="{Binding SenderVisibility}" x:Name="imgSender" Source="Assets/button_register.png" Stretch="None" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="8,15,8,8" />
<TextBlock Text="{Binding Sender}" FontSize="18" Foreground="Black" FontWeight="Bold" HorizontalAlignment="Center" Margin="0,12,0,0"/>
<Image x:Name="imgReceiver" Source="Assets/button_register.png" Grid.Row="1" Stretch="None" VerticalAlignment="Top" Margin="4,0" />
<TextBlock Text="{Binding Receiver}" FontSize="18" Foreground="Black" FontWeight="Bold" HorizontalAlignment="Center" Grid.Row="1" VerticalAlignment="Top"/>
<Image Source="Assets/scroll_line_addcategory.png" Grid.Row="2" Stretch="None" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="4,8,4,0" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
And my Model Class is
public class User : INotifyPropertyChanged
{
private string sender = string.Empty;
private string receiver = string.Empty;
private string senderVisibility = string.Empty;
private string receiverVisibility = string.Empty;
public string Sender
{
get
{
return sender;
}
set
{
if (value != this.sender)
{
this.sender = value;
NotifyPropertyChanged("Sender");
}
}
}
public string Receiver
{
get
{
return this.receiver;
}
set
{
if (value != this.receiver)
{
this.receiver = value;
NotifyPropertyChanged("Receiver");
}
}
}
public string ReceiverVisibility
{
get
{
return this.receiverVisibility;
}
set
{
if (value != this.receiverVisibility)
{
this.receiverVisibility = value;
NotifyPropertyChanged("ReceiverVisibility");
}
}
}
public string SenderVisibility
{
get
{
return this.senderVisibility;
}
set
{
if (value != this.senderVisibility)
{
this.senderVisibility = value;
NotifyPropertyChanged("SenderVisibility");
}
}
}
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
If your ListView contains only one item you can easily subscribe to Loaded event of imgSender and then control it's Visibility.
private Image _imgSender;
void Image_Loaded(object sender, RoutedEventArgs e)
{
_imgSender = sender as Image();
}
void AnotherMethod()
{
if (_imgSender != null)
_imgSender.Visibility = Visibility.Collapsed;
}
EDIT
FOR MULTIPLE ITEMS
void HideImage(int elementIndex)
{
var container = lst1.ContainerFromIndex(elementIndex) as ListViewItem;
var imageSender = (container.Content as Grid).Children[0] as Image;
imageSender.Visibility = Visibility.Collapsed;
}
You can add a BooleanToVisibilityConverter
<Page.Resources>
<converter:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
</Page.Resources>
<ListView x:Name="lst1" Grid.ColumnSpan="2"
ItemsSource="{Binding TelecomCollection}">
<ListView.ItemTemplate>
<DataTemplate >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Image x:Name="imgSender" Source="Assets/button_register.png" Stretch="None" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="8,15,8,8"
Visibility="{Binding ShowImgReceiver, Converter={StaticResource BooleanToVisibilityConverter}}"/>
<TextBlock Text="{Binding Sender}" FontSize="18" Foreground="Black" FontWeight="Bold" HorizontalAlignment="Center" Margin="0,12,0,0"/>
<Image x:Name="imgReceiver" Source="Assets/button_register.png" Grid.Row="1" Stretch="None" VerticalAlignment="Top" Margin="4,0" />
<TextBlock Text="{Binding Receiver}" FontSize="18" Foreground="Black" FontWeight="Bold" HorizontalAlignment="Center" Grid.Row="1" VerticalAlignment="Top"/>
<Image Source="Assets/scroll_line_addcategory.png" Grid.Row="2" Stretch="None" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="4,8,4,0" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Then in your item class you can add ShowImgReceiver
public class Telecom
{
string Receiver {get; set;}
string Sender {get; set;}
bool ShowImgReceiver{get; set;}
}
In your binding class
public class ViewModel
{
public ObservableCollection<Telecom> TelecomCollection {get; set;}
}
If you want to make an item's image visibility Collapsed, then
TelecomCollection[0].ShowImgReceiver = false;
and to make it again Visible
TelecomCollection[0].ShowImgReceiver = true;
How can I go about splitting a WPF Button into 4 quadrants and customize it so that I can set Background Color binding for each quadrant separately with Binding Path to separate properties.
It is nice if Button also has property to control whether each quadrant is clickable or only one click event is raised as a whole for each quadrant.
Assuming that if you are talking about binding, then you are using MVVM pattern
In the View-XAML create a button and add 4 rectangles within the content of the button.
<Button HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Width="150" Height="150" Command="{Binding RectangleButtonClick}">
<Button.Content>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="75"/>
<RowDefinition Height="75"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="75"/>
<ColumnDefinition Width="75"/>
</Grid.ColumnDefinitions>
<Rectangle x:Name="SecondQuad" Grid.Row="0" Grid.Column="0" Fill="{Binding SecondQuadColor}" />
<Rectangle x:Name="FirstQuad" Grid.Row="0" Grid.Column="1" Fill="{Binding FirstQuadColor}"/>
<Rectangle x:Name="ThirdQuad" Grid.Row="1" Grid.Column="0" Fill="{Binding ThirdQuadColor}"/>
<Rectangle x:Name="FourthQuad" Grid.Row="1" Grid.Column="1" Fill="{Binding FourthQuadColor}"/>
</Grid>
</Button.Content>
</Button>
In your ViewModel
public class MyViewModel
{
private SolidColorBrush _FirstQuadColor;
public SolidColorBrush FirstQuadColor
{
get { return _FirstQuadColor; }
set { _FirstQuadColor = value; OnPropertyChanged("FirstQuadColor"); }
}
private SolidColorBrush _SecondQuadColor;
public SolidColorBrush SecondQuadColor
{
get { return _SecondQuadColor; }
set { _SecondQuadColor = value; OnPropertyChanged("SecondQuadColor"); }
}
private SolidColorBrush _ThirdQuadColor;
public SolidColorBrush ThirdQuadColor
{
get { return _ThirdQuadColor; }
set { _ThirdQuadColor = value; OnPropertyChanged("ThirdQuadColor"); }
}
private SolidColorBrush _FourthQuadColor;
public SolidColorBrush FourthQuadColor
{
get { return _FourthQuadColor; }
set { _FourthQuadColor = value; OnPropertyChanged("FourthQuadColor"); }
}
private ICommand _RectangleButtonClick;
public ICommand RectangleButtonClick
{
get { return _RectangleButtonClick; }
set { _RectangleButtonClick = value; OnPropertyChanged("RectangleButtonClick"); }
}
public MyViewModel()
{
RectangleButtonClick = new DelegateCommand(RectangleButtonClick_Execute);
FirstQuadColor = Brushes.Red;
SecondQuadColor = Brushes.Green;
ThirdQuadColor = Brushes.Blue;
FourthQuadColor = Brushes.Yellow;
}
void RectangleButtonClick_Execute()
{
var directlyOver = Mouse.DirectlyOver;
if (directlyOver is Rectangle)
{
var selectedRectangle = (directlyOver as Rectangle);
switch (selectedRectangle.Name)
{
case "FirstQuad" : Console.Write("First Quad clicked"); break;
case "SecondQuad": Console.Write("Second Quad clicked"); break;
case "ThirdQuad": Console.Write("Third Quad clicked"); break;
case "FourthQuad": Console.Write("Fourth Quad clicked"); break;
}
}
}
}
There are actually lots of different ways to do this, the best method will depend on the specifics of your implementation. I'll provide one method here but be advised it's by no means the best (particularly if you're doing MVVM, which you should be).
<Button x:Name="MyButton" Margin="93,92,68,77" >
<Button.Template>
<ControlTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100*" />
<ColumnDefinition Width="100*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="100*" />
<RowDefinition Height="100*" />
</Grid.RowDefinitions>
<Rectangle Grid.Column="0" Grid.Row="0" Fill="{Binding Brush00}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MouseDown="UserControl_MouseDown_1"/>
<Rectangle Grid.Column="0" Grid.Row="1" Fill="{Binding Brush01}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MouseDown="UserControl_MouseDown_2"/>
<Rectangle Grid.Column="1" Grid.Row="0" Fill="{Binding Brush10}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MouseDown="UserControl_MouseDown_3"/>
<Rectangle Grid.Column="1" Grid.Row="1" Fill="{Binding Brush11}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MouseDown="UserControl_MouseDown_4" />
</Grid>
</ControlTemplate>
</Button.Template>
</Button>
And then in the code behind:
public partial class MyParentWindow : Window
{
public MyParentWindow()
{
InitializeComponent();
this.MyButton.DataContext = new ButtonModel();
}
private void UserControl_MouseDown_1(object sender, RoutedEventArgs e)
{
}
private void UserControl_MouseDown_2(object sender, RoutedEventArgs e)
{
}
private void UserControl_MouseDown_3(object sender, RoutedEventArgs e)
{
}
private void UserControl_MouseDown_4(object sender, RoutedEventArgs e)
{
}
}
public class ButtonModel
{
public Brush Brush00 { get { return Brushes.Red; } }
public Brush Brush01 { get { return Brushes.Green; } }
public Brush Brush10 { get { return Brushes.Blue; } }
public Brush Brush11 { get { return Brushes.Yellow; } }
}
I wanted to created data bindable property inside a user control. And this user control contains inside a "Windows Runtime Component" project. I used below code to create property.
public MyItem CurrentItem
{
get { return (MyItem)GetValue(CurrentItemProperty); }
set { SetValue(CurrentItemProperty, value); }
}
// Using a DependencyProperty as the backing store for CurrentItem.
// This enables animation, styling, binding, etc...
public static readonly DependencyProperty CurrentItemProperty =
DependencyProperty.Register("CurrentItem", typeof(MyItem), typeof(CollapseUserControl), new PropertyMetadata(null));
When I compile the project I get below error.
Type 'HierachyLib.CollapseUserControl' contains externally visible field 'HierachyLib.CollapseUserControl.CurrentItemProperty'. Fields can be exposed only by structures.
Update 1 - Source code for whole class
public sealed partial class CollapseUserControl : UserControl, IHierarchyHeightFix
{
public MyItem CurrentItem
{
get { return (MyItem)GetValue(CurrentItemProperty); }
set { SetValue(CurrentItemProperty, value); }
}
// Using a DependencyProperty as the backing store for CurrentItem. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CurrentItemProperty =
DependencyProperty.Register("CurrentItem", typeof(MyItem), typeof(CollapseUserControl), new PropertyMetadata(null));
Boolean viewState = true;
public CollapseUserControl()
{
this.DataContext = CurrentItem;
this.InitializeComponent();
this.Loaded += CollapseUserControl_Loaded;
}
void CollapseUserControl_Loaded(object sender, RoutedEventArgs e)
{
LoadData();
if (this.Height.Equals(double.NaN))
{
this.Height = 50;
}
//this.Height = 50;
//this.Width = double.NaN;
}
private void LoadData()
{
if (CurrentItem != null)
{
if (CurrentItem.IsValueControl)
{
ChildItemContainer.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
ValueItem.Visibility = Windows.UI.Xaml.Visibility.Visible;
ValueItem.Text = CurrentItem.Value;
}
else
{
ChildItemContainer.Visibility = Windows.UI.Xaml.Visibility.Visible;
ValueItem.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
ChildItems.ItemsSource = CurrentItem.Childs;
//foreach (MyItem item in CurrentItem.Childs)
//{
// CollapseUserControl control = new CollapseUserControl();
// control.CurrentItem = item;
// ChildItems.Items.Add(control);
//}
ChildItems.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
}
}
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
if (viewState)
{
ChildItems.Visibility = Windows.UI.Xaml.Visibility.Visible;
//show.Begin();
}
else
{
//hide.Begin();
ChildItems.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
}
viewState = !viewState;
}
private void hide_Completed_1(object sender, object e)
{
ChildItems.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
}
private void show_Completed_1(object sender, object e)
{
}
}
Update 2 : XAML Code
<UserControl
x:Class="HierachyLib.CollapseUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:HierachyLib"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">
<UserControl.Resources>
<DataTemplate x:Key="ReviewsItemsTemplate">
<StackPanel Margin="0,0,0,20">
<TextBlock Text="TEST" />
<TextBlock Text="TEST"/>
</StackPanel>
</DataTemplate>
<ItemsPanelTemplate x:Key="ReviewsItemsPanelTemplate">
<StackPanel Margin="0,0,0,0" Width="Auto"/>
</ItemsPanelTemplate>
</UserControl.Resources>
<!--xmlns:my="clr-namespace:HierarchyCollapse"-->
<Grid>
<Grid Name="ChildItemContainer">
<Grid.RowDefinitions>
<RowDefinition Height="40" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Rectangle Grid.Row="0" Margin="0,0,70,0" Fill="Transparent" Canvas.ZIndex="4"/>
<ListView HorizontalContentAlignment="Stretch" Background="#FF6599CD" CanDragItems="False" CanReorderItems="False" Grid.Row="0"
ScrollViewer.VerticalScrollBarVisibility="Hidden" ScrollViewer.VerticalScrollMode="Disabled"
ScrollViewer.HorizontalScrollBarVisibility="Hidden" ScrollViewer.HorizontalScrollMode="Disabled">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Height="40">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
<TextBlock Text="Sample Text" FontSize="17" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="10,10,0,0" Canvas.ZIndex="10"/>
<Image PointerPressed="Button_Click_1" Grid.Column="1" HorizontalAlignment="Right" VerticalAlignment="Center" Source="Assets/arrw_right.png" Stretch="None" Margin="0,0,10,0"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
<ListViewItem />
</ListView>
<ListView Grid.Row="1"
IsHitTestVisible="True"
CanDragItems="True"
CanReorderItems="True"
AllowDrop="True"
Name="ChildItems"
SelectionMode="None"
IsItemClickEnabled="False">
<ListView.ItemTemplate>
<DataTemplate>
<local:CollapseUserControl CurrentItem="{Binding RelativeSource={RelativeSource Self}}" />
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Padding" Value="0"/>
<Setter Property="Margin" Value="0"/>
</Style>
</ListView.ItemContainerStyle>
</ListView>
</Grid>
<TextBlock Name="ValueItem" Margin="0,0,0,0" Height="40" FontSize="36"></TextBlock>
</Grid>
New error I get:
Failed to create a 'Windows.UI.Xaml.PropertyPath' from the text ''.
Error comes from <local:CollapseUserControl CurrentItem="{Binding RelativeSource={RelativeSource Self}}" />.
It seems like you can mark your property as internal and then it starts working...
internal static readonly DependencyProperty CurrentItemProperty...
EDIT*
A better approach that seems to be what the platform controls do is to have an actual CLR property that exposes the DependencyProperty object - something like this:
private static readonly DependencyProperty CurrentItemPropertyField =
DependencyProperty.Register/RegisterAttached(...);
internal static DependencyProperty CurrentItemProperty
{
get
{
return CurrentItemPropertyField;
}
}
This allows tools such as Blend to discover the properties.
You can use an automatic property setting the default value (from c# 5) like this:
public static DependencyProperty CurrentItemPropertyField { get; } =
DependencyProperty.Register("Value", typeof(string), typeof(MyControl), new PropertyMetadata("{No Value}"));
Works also for UWP applications