How to set ItemsPanelTemplate to a dynamically created Grid in code behind - c#

I've got this UserControl defined in XAML and would like to set the ItemsPanelTemplate dynamically in my code behind class (not in the XAML like in the example):
<UserControl>
<ItemsControl x:Name="Items">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid> <!-- I want to add this Grid definition in code behind -->
<Grid.ColumnDefinitions>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
</Grid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</UserControl>
I tried something like
this.Items.ItemsPanel.Template = new Grid();
but failed miserably. Any help?
Background:
I only know the number of grid columns and rows at runtime.

You can do as you want by creating MannualCode in code behind as:
1. Create a Method as following which will return a ItemsPanelTemplate
private ItemsPanelTemplate GetItemsPanelTemplate()
{
string xaml = #"<ItemsPanelTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
</Grid>
</ItemsPanelTemplate>";
return XamlReader.Parse(xaml) as ItemsPanelTemplate;
}
Now add this template in your Listbox ItemsPanel as:
MyListBox.ItemsPanel = GetItemsPanelTemplate();
This is working fine for me. Hope this will help.
Keep Coding....:)

You need to create an ItemsPanelTemplate and set it's VisualTree to a FrameworkElementFactory (deprecated) which creates the Grid, or use the XamlReader to parse a XAML-string which specifies the template.
This question contains usage examples of both methods (albeit for a different template property).
An easier method to manipulate the panel at runtime is outlined in this question.

In case that you still have some work to do with the elements, you should take the following (extended) code:
First we need a helper in order to get the element:
// --------------------------------------------------------------------
// This function fetches the WrapPanel from oVisual.
private WrapPanel m_FetchWrapPanel (Visual oVisual)
{
// WrapPanel to be returned
WrapPanel oWrapPanel = null;
// number of childs of oVisual
int iNumberChilds = VisualTreeHelper.GetChildrenCount (oVisual);
// and running through the childs
int i = 0;
while ( ( i < iNumberChilds ) && ( oWrapPanel == null ) )
{ // fetching visual
Visual oVisualChild =
( VisualTreeHelper.GetChild (oVisual, i) as Visual );
if ( ( oVisualChild is WrapPanel ) is true )
{ // found
oWrapPanel = ( oVisualChild as WrapPanel );
}
else
{ // checking the childs of oVisualChild
oWrapPanel = m_FetchWrapPanel (oVisualChild);
};
// checking next child
i++;
};
// returning WrapPanel
return (oWrapPanel);
}
Now we create the Panel (or something):
// --------------------------------------------------------------------
private void m_SettingTemplate ()
{
// the online doc recommends to parse the template
string xaml =
#"<ItemsPanelTemplate
xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
<WrapPanel ItemWidth=""150"" MaxWidth=""150""/>
</ItemsPanelTemplate>";
// assigning the template
oMyListView.ItemsPanel = ( System.Windows.Markup.XamlReader.Parse (xaml) as ItemsPanelTemplate );
// fetching the WrapPanel
WrapPanel oWrapPanel = m_WrapPanelAusVisualHolen (oMyListView);
Debug.Assert (oWrapPanel != null);
if ( oWrapPanel != null )
{ // adjusting the size of the WrapPanel to the ListView
Binding oBinding = new Binding ("ActualWidth");
oBinding.Source = oMyListView;
oWrapPanel.SetBinding (WrapPanel.MaxWidthProperty, oBinding);
};
}

Here's a XAML based program which uses ItemsPanelTemplate with a Grid:
MainWindow.xaml:
<Window x:Class="WpfTutorialStatusBarGrid.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:WpfTutorialStatusBarGrid"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<DockPanel>
<StatusBar DockPanel.Dock="Bottom">
<StatusBar.ItemsPanel>
<ItemsPanelTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</StatusBar.ItemsPanel>
<StatusBarItem Grid.Column="0">
<TextBlock Name="lblCursorPosition" />
</StatusBarItem>
<Separator Grid.Column="1"/>
<StatusBarItem Grid.Column="2">
<TextBlock Text="c:\temp\abc.txt"/>
</StatusBarItem>
<Separator Grid.Column="3"/>
<StatusBarItem Grid.Column="4">
<ProgressBar Value="50" Width="90" Height="16"/>
</StatusBarItem>
</StatusBar>
<TextBox AcceptsReturn="True" Name="txtEditor" SelectionChanged="TxtEditor_SelectionChanged"/>
</DockPanel>
</Window>
MainWindow.xaml.cs:
using System.Windows;
namespace WpfTutorialStatusBarGrid
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void TxtEditor_SelectionChanged(object sender, RoutedEventArgs e)
{
var row = txtEditor.GetLineIndexFromCharacterIndex(txtEditor.CaretIndex);
var col = txtEditor.CaretIndex - txtEditor.GetCharacterIndexFromLineIndex(row);
lblCursorPosition.Text = $"Line {row + 1}, Char {col + 1}";
}
}
}
It's a simple text editor with a status bar:
Here's the equivalent program with the code in C# instead of XAML:
MainWindow.xaml:
<Window x:Class="WpfTutorialStatusBarGridCs.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:WpfTutorialStatusBarGridCs"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
</Grid>
</Window>
MainWindow.xaml.cs:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
namespace WpfTutorialStatusBarGridCs
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var dock_panel = new DockPanel();
Content = dock_panel;
var status_bar = new StatusBar();
dock_panel.Children.Add(status_bar);
DockPanel.SetDock(status_bar, Dock.Bottom);
var items_panel_template = new ItemsPanelTemplate();
{
var grid_factory = new FrameworkElementFactory(typeof(Grid));
{
{
var col = new FrameworkElementFactory(typeof(ColumnDefinition));
col.SetValue(ColumnDefinition.WidthProperty, new GridLength(100));
grid_factory.AppendChild(col);
}
{
var col = new FrameworkElementFactory(typeof(ColumnDefinition));
col.SetValue(ColumnDefinition.WidthProperty, new GridLength(1, GridUnitType.Auto));
grid_factory.AppendChild(col);
}
{
var col = new FrameworkElementFactory(typeof(ColumnDefinition));
col.SetValue(ColumnDefinition.WidthProperty, new GridLength(1, GridUnitType.Star));
grid_factory.AppendChild(col);
}
{
var col = new FrameworkElementFactory(typeof(ColumnDefinition));
col.SetValue(ColumnDefinition.WidthProperty, new GridLength(1, GridUnitType.Auto));
grid_factory.AppendChild(col);
}
{
var col = new FrameworkElementFactory(typeof(ColumnDefinition));
col.SetValue(ColumnDefinition.WidthProperty, new GridLength(100));
grid_factory.AppendChild(col);
}
}
items_panel_template.VisualTree = grid_factory;
}
status_bar.ItemsPanel = items_panel_template;
var text_block = new TextBlock();
{
var status_bar_item = new StatusBarItem();
Grid.SetColumn(status_bar_item, 0);
status_bar_item.Content = text_block;
status_bar.Items.Add(status_bar_item);
}
{
var separator = new Separator();
Grid.SetColumn(separator, 1);
status_bar.Items.Add(separator);
}
{
var status_bar_item = new StatusBarItem();
Grid.SetColumn(status_bar_item, 2);
status_bar_item.Content = new TextBlock() { Text = "abc" };
status_bar.Items.Add(status_bar_item);
}
{
var separator = new Separator();
Grid.SetColumn(separator, 3);
status_bar.Items.Add(separator);
}
{
var status_bar_item = new StatusBarItem();
Grid.SetColumn(status_bar_item, 4);
status_bar_item.Content = new ProgressBar() { Value = 50, Width = 90, Height = 16 };
status_bar.Items.Add(status_bar_item);
}
{
var text_box = new TextBox() { AcceptsReturn = true };
text_box.SelectionChanged += (sender, e) =>
{
var row = text_box.GetLineIndexFromCharacterIndex(text_box.CaretIndex);
var col = text_box.CaretIndex - text_box.GetCharacterIndexFromLineIndex(row);
text_block.Text = $"Line {row + 1}, Char {col + 1}";
};
dock_panel.Children.Add(text_box);
}
}
}
}
The C# version is much more verbose. However, with the help of some extension methods, it can be written in a fluent style, eliminating the intermediate variables:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var text_block = new TextBlock();
Content = new DockPanel()
.AddChildren(
new StatusBar()
.SetDock(Dock.Bottom)
.SetItemsPanel(
new ItemsPanelTemplate()
.SetVisualTree(
new FrameworkElementFactory(typeof(Grid))
.AppendChildren(
new FrameworkElementFactory(typeof(ColumnDefinition))
.SetValue_(ColumnDefinition.WidthProperty, new GridLength(100)),
new FrameworkElementFactory(typeof(ColumnDefinition))
.SetValue_(ColumnDefinition.WidthProperty, new GridLength(1, GridUnitType.Auto)),
new FrameworkElementFactory(typeof(ColumnDefinition))
.SetValue_(ColumnDefinition.WidthProperty, new GridLength(1, GridUnitType.Star)),
new FrameworkElementFactory(typeof(ColumnDefinition))
.SetValue_(ColumnDefinition.WidthProperty, new GridLength(1, GridUnitType.Auto)),
new FrameworkElementFactory(typeof(ColumnDefinition))
.SetValue_(ColumnDefinition.WidthProperty, new GridLength(100)))))
.AddItems(
new StatusBarItem() { Content = text_block }.SetColumn(0),
new Separator().SetColumn(1),
new StatusBarItem() { Content = new TextBlock() { Text = "abc" } }.SetColumn(2),
new Separator().SetColumn(3),
new StatusBarItem() { Content = new ProgressBar() { Value = 50, Width = 90, Height = 16 } }.SetColumn(4)),
new TextBox() { AcceptsReturn = true }
.AddSelectionChanged(
(sender, e) =>
{
var box = sender as TextBox;
var row = box.GetLineIndexFromCharacterIndex(box.CaretIndex);
var col = box.CaretIndex - box.GetCharacterIndexFromLineIndex(row);
text_block.Text = $"Line {row + 1}, Char {col + 1}";
}));
}
}
Here are the extension methods used:
public static class Extensions
{
public static T SetDock<T>(this T element, Dock dock) where T : UIElement
{
DockPanel.SetDock(element, dock);
return element;
}
public static T SetColumn<T>(this T element, int value) where T : UIElement
{
Grid.SetColumn(element, value);
return element;
}
public static T SetValue_<T>(this T factory, DependencyProperty dp, object value) where T : FrameworkElementFactory
{
factory.SetValue(dp, value);
return factory;
}
public static T AppendChildren<T>(this T factory, params FrameworkElementFactory[] children) where T : FrameworkElementFactory
{
foreach (var child in children)
factory.AppendChild(child);
return factory;
}
public static T SetVisualTree<T>(this T template, FrameworkElementFactory factory) where T : FrameworkTemplate
{
template.VisualTree = factory;
return template;
}
public static T1 SetItemsPanel<T1,T2>(this T1 control, T2 template) where T1 : ItemsControl where T2 : ItemsPanelTemplate
{
control.ItemsPanel = template;
return control;
}
public static T AddItems<T>(this T control, params object[] items) where T : ItemsControl
{
foreach (var item in items)
control.Items.Add(item);
return control;
}
public static T AddSelectionChanged<T>(this T obj, RoutedEventHandler handler) where T : TextBoxBase
{
obj.SelectionChanged += handler;
return obj;
}
public static T1 AddChildren<T1>(this T1 panel, params UIElement[] elements) where T1 : Panel
{
foreach (var elt in elements)
panel.Children.Add(elt);
return panel;
}
}

For anyone else...
... A control based on the ItemsControl which has an Orientation property.
It uses the FrameworkElementFactory as in the previous answers:
public class OrientationItemsControl : ItemsControl
{
public static readonly DependencyProperty OrientationProperty = WrapPanel.OrientationProperty.AddOwner(typeof(OrientationItemsControl), new PropertyMetadata(Changed));
private static void Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is ItemsControl itemsControl && e.NewValue is Orientation orientation)
{
var factory = new FrameworkElementFactory(typeof(StackPanel));
factory.SetValue(OrientationProperty, orientation);
itemsControl.ItemsPanel = TemplateGenerator.CreateItemsPanelTemplate(factory);
}
}
public Orientation Orientation
{
get => (Orientation)GetValue(OrientationProperty);
set => SetValue(OrientationProperty, value);
}
}

Related

WPF Dynamic change of GridViewColumn CellTemplate c#

I'm trying to learn something about the ListView and now I'm solving this problem:
I have a listview defined in the behindcode. I would like to change gridviewcolumn celltemplate dynamically. For example by the use of checkbox or button, or other. Is it even possible?
Definition of my ListView is here:
lvUsers.ItemsSource = LoadListViewData();
GridView gridview = new GridView();
lvUsers.View = gridview;
DataTemplate templateCheck = new DataTemplate();
FrameworkElementFactory factoryContentControlCheck = new FrameworkElementFactory(typeof(VsCheckBox));
factoryContentControlCheck.SetValue(VsCheckBox.MarginProperty, new Thickness(0, 0, 0, 0));
DataTemplate templateBorder = new DataTemplate();
FrameworkElementFactory factoryContentControlBorder = new FrameworkElementFactory(typeof(Border));
factoryContentControlBorder.SetValue(Border.MarginProperty, new Thickness(0, 0, 10, 0));
factoryContentControlBorder.SetValue(Border.WidthProperty, Width = 10);
factoryContentControlBorder.SetValue(Border.HeightProperty, Height = 10);
factoryContentControlBorder.SetValue(Border.BackgroundProperty, Brushes.Red);
DataTemplate templateAge = new DataTemplate();
FrameworkElementFactory factoryContentControlAge = new FrameworkElementFactory(typeof(ContentControl));
factoryContentControlName.SetValue(ContentControl.MarginProperty, new Thickness(0, 0, 10, 0));
factoryContentControlAge.SetValue(ContentControl.VerticalAlignmentProperty, VerticalAlignment.Center);
factoryContentControlAge.SetValue(ContentControl.HorizontalAlignmentProperty, HorizontalAlignment.Right);
factoryContentControlAge.SetBinding(ContentControl.ContentProperty, new Binding("Age"));
DataTemplate templateStack = new DataTemplate();
FrameworkElementFactory factoryContentControlStack = new FrameworkElementFactory(typeof(StackPanel));
factoryContentControlStack.SetValue(StackPanel.MarginProperty, new Thickness(10, 0, 0, 0));
factoryContentControlStack.SetValue(StackPanel.OrientationProperty, Orientation.Horizontal);
factoryContentControlStack.SetValue(StackPanel.VerticalAlignmentProperty, VerticalAlignment.Center);
factoryContentControlStack.AppendChild(factoryContentControlCheck);
factoryContentControlStack.AppendChild(factoryContentControlBorder);
templateStack.VisualTree = factoryContentControlStack;
DataTemplate templateStack1 = new DataTemplate();
FrameworkElementFactory factoryContentControlStack1 = new FrameworkElementFactory(typeof(StackPanel));
factoryContentControlStack1.SetValue(StackPanel.MarginProperty, new Thickness(10, 0, 0, 0));
factoryContentControlStack1.SetValue(StackPanel.OrientationProperty, Orientation.Horizontal);
factoryContentControlStack1.SetValue(StackPanel.HorizontalAlignmentProperty, HorizontalAlignment.Right);
factoryContentControlStack1.SetValue(StackPanel.VerticalAlignmentProperty, VerticalAlignment.Center);
factoryContentControlStack1.AppendChild(factoryContentControlAge);
templateStack1.VisualTree = factoryContentControlStack1;
GridViewColumn colStack = new GridViewColumn();
colStack.Header = "Stack";
colStack.CellTemplate = templateStack;
gridview.Columns.Add(colStack);
I would like to change CellTemplate of colStack to templateStack1 in runtime by the checking a checkbox or button click.
Thank you for any of your ideas.
You can make use of DataTrigger in order to change dynamically the ContentTemplate of your columns. Here is an example using XAML:
<Window x:Class="WpfApp.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"
mc:Ignorable="d"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<CheckBox x:Name="TemplateChanger" Content="Change template"
IsChecked="{Binding IsChecked}"/>
<DataGrid x:Name="DataGrid" Grid.Row="1" AutoGenerateColumns="False"
ItemsSource="{Binding Items}">
<DataGrid.Columns>
<DataGridTemplateColumn Header="My column" IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Foo}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellStyle>
<Style TargetType="DataGridCell">
<Style.Triggers>
<DataTrigger Binding="{Binding DataContext.IsChecked, RelativeSource={RelativeSource AncestorType=DataGrid}}" Value="True">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="fsdfsdf"/>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGridTemplateColumn.CellStyle>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
And the codebehind file:
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using WpfApp.Annotations;
namespace WpfApp
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : INotifyPropertyChanged
{
private bool _isChecked;
public MainWindow()
{
InitializeComponent();
Items.Add(new Item {Foo = "Foo1"});
Items.Add(new Item {Foo = "Foo2"});
Items.Add(new Item {Foo = "Foo3"});
Items.Add(new Item {Foo = "Foo4"});
}
public bool IsChecked
{
get => _isChecked;
set
{
_isChecked = value;
OnPropertyChanged();
}
}
public ObservableCollection<Item> Items { get; } = new ObservableCollection<Item>();
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class Item
{
public string Foo { get; set; }
}
}
The result is that whenever you toggle the checkbox's IsChecked property the content template of the cell for the given column changes too.
EDIT How to do it with code behind only
For completness sake here is how you can achieve this with code behind only:
var datagrid = new DataGrid {AutoGenerateColumns = false};
Grid.SetRow(datagrid,1);
RootGrid.Children.Add(datagrid);
var templateColumn = new DataGridTemplateColumn
{
Header = "My column",
IsReadOnly = true
};
var cellTemplate = new DataTemplate();
var factory = new FrameworkElementFactory(typeof(TextBlock));
factory.SetBinding(TextBlock.TextProperty, new Binding("Foo"));
var style = new Style(typeof(DataGridCell));
var trigger = new DataTrigger();
var triggerBinding = new Binding("DataContext.IsChecked")
{
RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(DataGrid), 1)
};
trigger.Binding = triggerBinding;
trigger.Value = true;
var triggerSetter = new Setter {Property = ContentTemplateProperty};
var triggerTemplate = new DataTemplate();
var anotherFactory = new FrameworkElementFactory(typeof(TextBlock));
anotherFactory.SetValue(TextBlock.TextProperty,"lol");
triggerTemplate.VisualTree = anotherFactory;
triggerSetter.Value = triggerTemplate;
trigger.Setters.Add(triggerSetter);
style.Triggers.Add(trigger);
templateColumn.CellStyle = style;
cellTemplate.VisualTree = factory;
templateColumn.CellTemplate = cellTemplate;
datagrid.Columns.Add(templateColumn);
datagrid.ItemsSource = Items;
IMHO this way looks a little bit messy, but the decision is yours =)

C# XCeed creating PropertyGrid dynamically by code

I'm trying to create the PropertyGrid dynamically in code. So far, I can create and customize a PropertyGrid inside the XAML credits to: XCeed PropertyGrid customizing IntegerUpDown
:
MainWindow.xaml.cs:
public MainWindow()
{
InitializeComponent();
Sample or = new Sample();
pg.SelectedObject = or;
pg.ShowAdvancedOptions = true;
EditorDefinition ed = new EditorDefinition();
PropertyDefinition pd = new PropertyDefinition();
pd.Name = "Value";
ed.PropertyDefinitions.Add(pd);
DataTemplate dt = new DataTemplate();
FrameworkElementFactory fac = new FrameworkElementFactory(typeof(PropertyGridEditorIntegerUpDown));
dt.VisualTree = fac;
DependencyProperty dp = PropertyGridEditorIntegerUpDown.DefaultValueProperty;
fac.SetValue(dp, 10);
ed.EditorTemplate = dt;
pg.EditorDefinitions.Add(ed);
}
MainWindow.xaml:
<Window
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:WpfApp1"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit" xmlns:xcdg="http://schemas.xceed.com/wpf/xaml/datagrid" x:Class="WpfApp1.MainWindow"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<xctk:PropertyGrid x:Name="pg">
<xctk:PropertyGrid.EditorDefinitions >
<xctk:EditorDefinition >
<xctk:EditorDefinition.PropertiesDefinitions >
< xctk:PropertyDefinition Name = "Value" />
</xctk:EditorDefinition.PropertiesDefinitions >
<xctk:EditorDefinition.EditorTemplate >
<DataTemplate >
<xctk:PropertyGridEditorIntegerUpDown Increment = "10" Value = "{Binding Value}" Maximum = "40" MinHeight = "0" Minimum = "-30" />
</DataTemplate >
</xctk:EditorDefinition.EditorTemplate >
</xctk:EditorDefinition >
</xctk:PropertyGrid.EditorDefinitions >
</xctk:PropertyGrid >
</Window>
and the Sample class:
public class Sample
{
private int _Value;
#region Public Properties
[Category("Sample")]
[DisplayName("Sample Value")]
[DefaultValue(3)]
public int Value { set; get; }
#endregion
}
This would be the equivalent code:
EditorDefinition ed = new EditorDefinition();
PropertyDefinition pd = new PropertyDefinition();
pd.Name = "Value";
ed.PropertiesDefinitions.Add(pd);
FrameworkElementFactory fac = new FrameworkElementFactory(typeof(PropertyGridEditorIntegerUpDown));
fac.SetBinding(PropertyGridEditorIntegerUpDown.ValueProperty, new Binding("Value"));
fac.SetValue(PropertyGridEditorIntegerUpDown.IncrementProperty, 10);
DataTemplate dt = new DataTemplate { VisualTree = fac };
dt.Seal();
ed.EditorTemplate = dt;
pg.EditorDefinitions.Add(ed);

Custom control not displaying correctly

I'm trying to develop a WPF custom control that can be used to overlay other controls, effectively dimming them out so as to make it clear that they are not usable. This is similar to the effect you see on many web sites, where they grey out the background page when a pop-up is shown.
Trouble is, when it runs, instead of showing the contained controls dimly, they just disappear. I'll show the code below, along with a very simple sample usage.
Here is the code for control itself (namespace and usings omitted to save a bit of space)...
public class OverlayDisableControl : UserControl {
protected override void OnInitialized(EventArgs e) {
base.OnInitialized(e);
VerticalAlignment = VerticalAlignment.Stretch;
HorizontalAlignment = HorizontalAlignment.Stretch;
Grid grid = new Grid();
ContentPresenter content = new ContentPresenter {
Name = "content",
Content = Content
};
grid.Children.Add(content);
Grid overlay = new Grid {
Name = "Overlay",
Visibility = Visibility.Collapsed
};
Border background = new Border {
Name = "background",
VerticalAlignment = VerticalAlignment.Stretch,
HorizontalAlignment = HorizontalAlignment.Stretch,
Background = new SolidColorBrush(Colors.LightGray),
Opacity = .6
};
overlay.Children.Add(background);
grid.Children.Add(overlay);
Content = grid;
}
public static readonly DependencyProperty OverlayVisibleProperty =
DependencyProperty.Register("OverlayVisible", typeof(bool),
typeof(OverlayDisableControl),
new FrameworkPropertyMetadata(SetOverlayVisibleStatic));
public bool OverlayVisible {
get {
return (bool) GetValue(OverlayVisibleProperty);
}
set {
SetValue(OverlayVisibleProperty, value);
}
}
private static void SetOverlayVisibleStatic(DependencyObject d, DependencyPropertyChangedEventArgs e) {
(d as OverlayDisableControl).SetOverlayVisible(d as OverlayDisableControl, (bool) e.NewValue);
}
private void SetOverlayVisible(OverlayDisableControl odc, bool visible) {
if (visible) {
DoubleAnimation anim = new DoubleAnimation {
From = 0,
To = 1, // Visible
Duration = new Duration(TimeSpan.FromMilliseconds(350)),
EasingFunction = new QuadraticEase {
EasingMode = EasingMode.EaseInOut
}
};
odc.Visibility = Visibility.Visible;
odc.BeginAnimation(OpacityProperty, anim);
} else {
DoubleAnimation anim = new DoubleAnimation {
From = 1,
To = 0, // Invisible
Duration = new Duration(TimeSpan.FromMilliseconds(350)),
EasingFunction = new QuadraticEase {
EasingMode = EasingMode.EaseInOut
}
};
anim.Completed += (s1, e1) => {
odc.Visibility = Visibility.Collapsed;
};
odc.BeginAnimation(OpacityProperty, anim);
}
}
}
...and here is a sample usage. This is all you need, no code-behind, just drop this onto a window. The controls inside the GroupBox are just there for tesing...
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<CheckBox Content="Show?"
Margin="3"
Name="ShowChk"
IsChecked="True" />
</StackPanel>
<local:OverlayDisableControl OverlayVisible="{Binding ElementName=ShowChk, Path=IsChecked, Mode=TwoWay}"
Grid.Row="1">
<GroupBox Header="Gratuitous controls"
Margin="3">
<StackPanel Orientation="Vertical">
<TextBlock Text="This is some text"
Margin="3" />
<TextBox Margin="3" />
<Button Content="Save"
Margin="3" />
</StackPanel>
</GroupBox>
</local:OverlayDisableControl>
</Grid>
Anyone any idea what I've done wrong?
You're animating / changing visibility of the UserControl itself, while it's the Grid overlay you're after.
Changes to your code:
public class OverlayDisableControl : UserControl
{
private Grid overlay = new Grid
{
Name = "Overlay",
Visibility = Visibility.Collapsed
};
protected override void OnInitialized(EventArgs e)
{
base.OnInitialized(e);
...
//Grid overlay = new Grid
//{
// Name = "Overlay",
// Visibility = Visibility.Collapsed
//};
...
}
...
private static void SetOverlayVisibleStatic(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
(d as OverlayDisableControl).SetOverlayVisible((bool)e.NewValue);
}
private void SetOverlayVisible(bool visible)
{
if (visible)
{
DoubleAnimation anim = new DoubleAnimation
{
...
};
overlay.Visibility = Visibility.Visible;
overlay.BeginAnimation(OpacityProperty, anim);
}
else
{
DoubleAnimation anim = new DoubleAnimation
{
...
};
anim.Completed += (s1, e1) => {
overlay.Visibility = Visibility.Collapsed;
};
overlay.BeginAnimation(OpacityProperty, anim);
}
}
}

Wp8 application custom control which has some dynamic buttons , shows nothing on mainpage

Problem while programmatically generating buttons in a user control of windows phone, and using this user control to mainpage.xaml but there are no buttons shown when application runs.
here is the code snippet which i am using, Thanks !
usercontrol.xaml:
<ScrollViewer >
<StackPanel x:Name="Panel">
<ContentControl x:Name="container"></ContentControl>
</StackPanel>
</ScrollViewer>
usercontrol.xaml.cs:
public LoginInterfaceControl()
{
InitializeComponent();
this.container = new ContentControl();
this.Panel = new StackPanel();
}
public LoginInterfaceControl(string Api_key)
{
InitializeComponent();
this.Panel = new StackPanel();
this.container = new ContentControl();
loginWP_DownloadString(Api_key);
}
public async void loginWP_DownloadString(string key)
{
InitializeComponent();
string cont;
using (HttpClient client = new HttpClient())
{
var result = await client.GetAsync("http://cdn.loginradius.com/interface/json/" + key + ".json");
if (result.StatusCode == HttpStatusCode.OK)
{
cont = await result.Content.ReadAsStringAsync();
MessageBox.Show(cont);
}
else
{
cont = await result.Content.ReadAsStringAsync();
MessageBox.Show(cont);
}
if (!string.IsNullOrEmpty(cont))
{
var root1 = JsonConvert.DeserializeObject<RootObject>(cont);
int no = 1;
foreach (var provider in root1.Providers)
{
no++;
Button newBtn = new Button()
{
Content = provider.Name.ToString(),
Name = provider.Name.ToString(),
//Width = 88,
//Height = 77,
Visibility = System.Windows.Visibility.Visible,
//Margin = new Thickness(5 + 20, 5, 5, 5),
Background = new SolidColorBrush(Colors.Black),
VerticalAlignment =VerticalAlignment.Center,
Opacity=0.5
};
newBtn.Click += google_click;
System.Windows.Visibility.Visible;
container.Opacity = 0.5;
this.container.Content = newBtn;
}
}
}
Mainpage.xaml:
<Grid xmlns:src="clr-namespace:LRDemo"
Background="White" Margin="10,0,-10,186" Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<src:LoginInterfaceControl Grid.Row="0"/>
<!--<src:LoginInterfaceControl Grid.Row="1" Margin="0,15,0,0"/>-->
</Grid>
usercontrol.xaml
<ScrollViewer>
<ContentControl x:Name="container">
<StackPanel x:Name="Panel">
</StackPanel>
</ContentControl>
</ScrollViewer>
there is no need to again create stackpanel and contentcontrol in constructor of usercontrol because they are already there in usercontrol structure.
Contentcontrol can hold content that is assign to it last so I took stackpanel into contentcontol.
usercontrol.xaml.cs
public LoginInterfaceControl()
{
this.InitializeComponent();
abc();
}
public void abc()
{
for (int i = 0; i <= 5; i++)
{
Button newBtn = new Button()
{
Content = "name" + i,
Name = "name" + i,
Background = new SolidColorBrush(Colors.Black),
VerticalAlignment = VerticalAlignment.Center,
Opacity = 0.5
};
newBtn.Click += newBtn_Click;
container.Opacity = 0.5;
this.Panel.Children.Add(newBtn);
}
}
P.S : I do not know your exact need so I took static methods to add buttons.

WPF ComboBox Hide (Disable) DropDown Button Programmatically

I would like to know how to disable ComboBox DropDown Button Programmatically. I had seen many similar subjects but all of these have a XAML solution.
By the way, if someone know how to disable all ComboBox control design and left visible only item template it can be helpful too.
UPDATE
its my XAML definition
<ComboBox Name="lang_ComboBox" SelectionChanged="LanguageSelection_ComboBox_SelectionChanged"/>
And there is how i use it:
String text = "dorf";
BitmapImage image = new BitmapImage(new Uri("http://img88.imageshack.us/img88/4351/butchermi4.png"));
lang_ComboBox.Width = 100;
lang_ComboBox.Height = 30;
Grid sp;
for (int i = 0; i < 5; i++)
{
ColumnDefinition gridCol1 = new ColumnDefinition();
gridCol1.Width = new GridLength(30.0);
ColumnDefinition gridCol2 = new ColumnDefinition();
gridCol2.Width = new GridLength(70.0);
sp = new Grid()
{
Width = 100,
Height = 30
};
Image im = new Image()
{
Source = image,
Width = 25,
Height = 25
};
Label la = new Label()
{
Content = text
};
sp.ColumnDefinitions.Add(gridCol1);
sp.ColumnDefinitions.Add(gridCol2);
Grid.SetColumn(im, 0);
Grid.SetColumn(la, 1);
sp.Children.Add(la);
sp.Children.Add(im);
lang_ComboBox.Items.Add(sp);
}
UPDATE 2
Hmmm I get it now, I use wrong word. It should be "Hide" control design and still can choose from a list. My bad sorry. But i know how i can solve it with Anatoliy Nokolaev's Code. To hide control design i use:
ToggleButton dropDownButton = GetFirstChildOfType<ToggleButton>(lang_ComboBox);
dropDownButton.Visibility = System.Windows.Visibility.Collapsed;
Unwanted behavior is now only that i cant show combobox dropdownmenu, but I'll invoke it programmatically by add on click event and should be good.
If there is any easiest way to do this tell me :).
To disable only the ToggleButton in ComboBox programmatically, you need to find this in the ComboBox control using VisualTreeHelper and assign a property IsEnabled to false, like this:
XAML
<Window x:Class="DisableComboBoxButton.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
Loaded="Window_Loaded">
<StackPanel>
<ComboBox Name="comboBox"
Width="100"
Height="25"
SelectedIndex="0">
<ComboBoxItem>Test1</ComboBoxItem>
<ComboBoxItem>Test2</ComboBoxItem>
<ComboBoxItem>Test3</ComboBoxItem>
</ComboBox>
<ComboBox Name="AllComboBoxDisabled"
Width="100"
Height="25"
IsEnabled="False"
SelectedIndex="0">
<ComboBoxItem>Test1</ComboBoxItem>
<ComboBoxItem>Test2</ComboBoxItem>
<ComboBoxItem>Test3</ComboBoxItem>
</ComboBox>
</StackPanel>
</Window>
Code-behind
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
ToggleButton dropDownButton = GetFirstChildOfType<ToggleButton>(comboBox);
dropDownButton.IsEnabled = false;
}
public static T GetFirstChildOfType<T>(DependencyObject dependencyObject) where T : DependencyObject
{
if (dependencyObject == null)
{
return null;
}
for (var i = 0; i < VisualTreeHelper.GetChildrenCount(dependencyObject); i++)
{
var child = VisualTreeHelper.GetChild(dependencyObject, i);
var result = (child as T) ?? GetFirstChildOfType<T>(child);
if (result != null)
{
return result;
}
}
return null;
}
}
Output
Notes
Always use GetFirstChildOfType() function only when the control will be fully loaded, otherwise it will not find it and give null. In this case, I put this code in the event Window_Loaded which says that all the controls of the Window successfully load.
Edit: another version
Not to say that this version is easier to implement, but it would be more correct and a bit easier to use.
So, we need a template for your ComboBox, because it allows access to elements that are within the control. Just like that, the ToggleButton can not be accessed from both the code and of XAML.
We create attached dependency property that will serve the current ComboBox another property, such as which will give access to our button Visibility.
Our property Visibility:
public static class ButtonExt
{
public static readonly DependencyProperty VisibilityProperty;
public static void SetVisibility(DependencyObject DepObject, Visibility value)
{
DepObject.SetValue(VisibilityProperty, value);
}
public static Visibility GetVisibility(DependencyObject DepObject)
{
return (Visibility)DepObject.GetValue(VisibilityProperty);
}
static ButtonExt()
{
PropertyMetadata VisibiltyPropertyMetadata = new PropertyMetadata(Visibility.Collapsed);
VisibilityProperty = DependencyProperty.RegisterAttached("Visibility",
typeof(Visibility),
typeof(ButtonExt),
VisibiltyPropertyMetadata);
}
}
Setter property in ComboBox template (skip version, full version see in project in App.xaml file):
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBox}">
<Grid>
<ToggleButton Name="ToggleButton"
Template="{StaticResource ComboBoxToggleButton}"
IsChecked="{Binding Path=IsDropDownOpen,
Mode=TwoWay,
RelativeSource={RelativeSource TemplatedParent}}"
Visibility="{TemplateBinding PropertiesExtension:ButtonExt.Visibility}" // <------ Here
Grid.Column="2"
Focusable="False"
ClickMode="Press" />
Now, we are setting this property like this:
<ComboBox Name="comboBox"
Style="{StaticResource ComboBoxBaseStyle}"
PropertiesExtension:ButtonExt.Visibility="Visible"
Width="100"
Height="30"
SelectedIndex="0">
<ComboBoxItem>Test1</ComboBoxItem>
<ComboBoxItem>Test2</ComboBoxItem>
<ComboBoxItem>Test3</ComboBoxItem>
</ComboBox>
or in code-behind via Click event handlers:
private void HideButton_Click(object sender, RoutedEventArgs e)
{
ButtonExt.SetVisibility(comboBox, Visibility.Hidden);
}
private void ShowButton_Click(object sender, RoutedEventArgs e)
{
ButtonExt.SetVisibility(comboBox, Visibility.Visible);
}
Full version of example project is here.
Try with this
Dispatcher.BeginInvoke(new Action(() =>
{
ToggleButton dropDownButton = GetFirstChildOfType<ToggleButton>(cboMedicos);
if (dropDownButton != null)
{
dropDownButton.IsEnabled = false;
}
}), System.Windows.Threading.DispatcherPriority.Render);
public static T GetFirstChildOfType<T>(DependencyObject dependencyObject) where T : DependencyObject
{
if (dependencyObject == null)
{
return null;
}
for (var i = 0; i < VisualTreeHelper.GetChildrenCount(dependencyObject); i++)
{
var child = VisualTreeHelper.GetChild(dependencyObject, i);
var result = (child as T) ?? GetFirstChildOfType<T>(child);
if (result != null)
{
return result;
}
}
return null;
}

Categories