How to disable button but force children to be enabled? - c#

I am trying to figure out how I can set the "IsEnabled" property to false on a Button but then have the children (in my case a Combobox) be enabled. It seems the children inherit the property value from the parent element (in this case the disabled button) and therefore also disables itself. How can I prevent this?
I have tried to lookup answers but they all use "Override Metadata" which WinUI3 and Windows App SDK do not contain.
<Button
x:Name="Button1"
IsEnabled="False">
<Button.Content>
<ComboBox x:Name="ComboBox1" />
</Button.Content>
</Button>

You can create a custom control like this:
Generic.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Buttons">
<Style TargetType="local:CustomButton">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:CustomButton">
<Grid
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Button
x:Name="ButtonControl"
HorizontalAlignment="Center"
VerticalAlignment="Center"
IsEnabled="{TemplateBinding IsButtonEnabled}" />
<ContentControl
x:Name="ContentControl"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Content="{TemplateBinding Content}"
IsEnabled="{TemplateBinding IsContentEnabled}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
CustomButton.cs
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
namespace Buttons;
[TemplatePart(Name = nameof(ButtonControl), Type = typeof(Button))]
[TemplatePart(Name = nameof(ContentControl), Type = typeof(ContentControl))]
public sealed class CustomButton : ContentControl
{
public static readonly DependencyProperty IsButtonEnabledProperty = DependencyProperty.Register(
nameof(IsButtonEnabled),
typeof(bool),
typeof(CustomButton),
new PropertyMetadata(true));
public static readonly DependencyProperty IsContentEnabledProperty = DependencyProperty.Register(
nameof(IsContentEnabled),
typeof(bool),
typeof(CustomButton),
new PropertyMetadata(true));
public CustomButton()
{
this.DefaultStyleKey = typeof(CustomButton);
}
public bool IsButtonEnabled
{
get => (bool)GetValue(IsButtonEnabledProperty);
set => SetValue(IsButtonEnabledProperty, value);
}
public bool IsContentEnabled
{
get => (bool)GetValue(IsContentEnabledProperty);
set => SetValue(IsContentEnabledProperty, value);
}
private Button? ButtonControl { get; set; }
private ContentControl? ContentControl { get; set; }
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
ButtonControl = GetTemplateChild(nameof(ButtonControl)) as Button;
if (GetTemplateChild(nameof(ContentControl)) is ContentControl contentControl)
{
if (ContentControl is not null)
{
ContentControl.SizeChanged -= ContentControl_SizeChanged;
}
ContentControl = contentControl;
ContentControl.SizeChanged += ContentControl_SizeChanged;
}
}
private void ContentControl_SizeChanged(object sender, SizeChangedEventArgs e)
{
if (sender is ContentControl contentControl &&
ButtonControl is not null)
{
ButtonControl.Width = contentControl.ActualWidth + 20.0;
ButtonControl.Height = contentControl.ActualHeight + 20.0;
}
}
}
And use it like this:
MainWindow.xaml
<Grid>
<local:CustomButton
IsButtonEnabled="False"
IsContentEnabled="True">
<ComboBox
SelectedIndex="0"
SelectionChanged="ComboBox_SelectionChanged">
<x:String>Blue</x:String>
<x:String>Green</x:String>
<x:String>Red</x:String>
</ComboBox>
</local:CustomButton>
</Grid>

Related

dynamic property not working well with DependencyProperties

My requirement is Binding dynamic property to my Value (double) property of Custom control.But it not working as expected.
Below is the code :
Simple customcontrol part :
xaml
<Style TargetType="{x:Type local:CustomControl1}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:CustomControl1}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<TextBox x:Name="PART_TextBox" Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
c#
public class CustomControl1 : Control
{
public double? Value
{
get { return (double?)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
// Using a DependencyProperty as the backing store for Value. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(double?), typeof(CustomControl1), new PropertyMetadata(null, new PropertyChangedCallback(OnValueChanged), new CoerceValueCallback(CoerceValueChange)));
private static object CoerceValueChange(DependencyObject d, object baseValue)
{
return baseValue;
}
private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((CustomControl1)d).OnValueChanged(e);
}
private void OnValueChanged(DependencyPropertyChangedEventArgs e)
{
if (tb != null && e.NewValue != null)
tb.Text = e.NewValue.ToString();
else
tb.Text = string.Empty;
}
static CustomControl1()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl1), new FrameworkPropertyMetadata(typeof(CustomControl1)));
}
TextBox tb = null;
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
tb = base.GetTemplateChild("PART_TextBox") as TextBox;
}
}
here goes the usage :
xaml
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0">
<Label Content="Double TextBox without Converter" />
<Label Content="Double TextBox with Converter" />
<Label Content="MS TextBox" />
<Button Content="Button" Click="Button_Click_1"/>
</StackPanel>
<StackPanel Grid.Column="1">
<cc:CustomControl1 Value="{Binding MyValue}" Height="40" Width="200" Background="Red"/>
<TextBox Height="30" Text="{Binding MyValue}" />
</StackPanel>
</Grid>
c#
public partial class MainWindow : Window, INotifyPropertyChanged
{
private dynamic myValue;
public dynamic MyValue
{
get { return myValue; }
set { myValue = value; RaisePropertyChanged("MyValue"); }
}
public MainWindow()
{
InitializeComponent();
this.myValue = 3;
this.DataContext = this;
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
this.myValue = 5;
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string name)
{
if (PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
}
the coerce's base value is always null,but if i use converter in binding it works as expected.
but i want to use like normal property , Please help me on this.
binding works perfectly if i use TextBox,it is not the issue ,, i'm facing issue while i use DP's in CustomControl
Regards,
Kumar
Found answer from here..............
http://social.msdn.microsoft.com/Forums/vstudio/en-US/7d0f0a90-b0b8-45c9-9ec9-76517c8ea4af/dynamic-property-not-working-well-with-dependencyproperties?forum=wpf

programmatically set dynamic resource but FrameWorkElement do not update when ResourceDictionary changed?

Im am using a dynamic resource dictionaries to translate my GUI-elements.
The Dictionaries are loaded on startup or could be changed during runtime.
Works very well!
Now i have to add some GUI-elements programmatically ..
But they will not update after changing the translation..
Here is how i "translate" the GUI-elements in XAML:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:tests.Dialogs" x:Class="tests.Dialogs.Dlg_Main"
xmlns:Translator="clr-namespace:tests.Translation"
Title="{DynamicResource DLG_MAIN_TITLE}"
Height="356" Width="711"
/>
This is my MenuItem Class which is added to a ListBox:
public class MenuItem : FrameworkElement
{
public MenuItem (string resourceKey, ClickAction action)
{
Action=action;
this.SetResourceReference(ContentProperty, resourceKey);
}
public void DoAction ()
{
if (Action!=null)
{
Action();
}
}
public delegate void ClickAction ();
private ClickAction Action;
public Object Content
{
get { return (Object)GetValue(ContentProperty); }
set { SetValue(ContentProperty, value); }
}
// Using a DependencyProperty as the backing store for Name. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ContentProperty=DependencyProperty.Register("Content", typeof(Object), typeof(MenuItem), new PropertyMetadata("leer?"));
}
And this is the XAML Style for the ListBox:
<SolidColorBrush x:Key="ItemBrush" Color="Transparent" />
<SolidColorBrush x:Key="SelectedItemBrush" Color="Orange" />
<Style x:Key="RoundedItem" TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border Name="ItemBorder" BorderBrush="Transparent" BorderThickness="8,0,0,0" Margin="0" Padding="5" Background="{StaticResource ItemBrush}">
<StackPanel Orientation="Horizontal">
<TextBlock Margin="10,0,0,0" Text="{Binding Content.Content, RelativeSource={RelativeSource TemplatedParent}}" FontSize="18" FontWeight="Normal" VerticalAlignment="Center" />
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
ListBox used like this in XAML:
<ListBox
x:Name="gui_listbox_menu"
ItemContainerStyle="{StaticResource RoundedItem}"
Background="Transparent"
SelectionChanged="gui_listbox_menu_SelectionChanged"
Margin="0,20,0,0"
ItemsSource="{Binding MenuItems, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:Dlg_Main}}}"
/>
After startup the MenuItems have the correct translation, so the Reference works?!
but if i change the language during runtime only the MenuItems still showing the old language!
If i add an Button programmatically and set its ReferenceSource to the DynamicResource its content will change during runtime, too!
Button btn_test=new Button();
btn_test.Content="test";
btn_test.Width=100;
btn_test.Height=100;
gui_tab_settings_grid.Children.Add(btn_test);
btn_test.SetResourceReference(Button.ContentProperty, "DLG_MAIN_TITLE");
But my MenuItems do not change during runtime??!
Any help would be welcome!
I don't know whats the difference, but here is the "new" MenuItem class..
It derives now ListBoxItem ..
public class MenuItem : ListBoxItem
{
public MenuItem (string resourceKey, ClickAction action)
{
Action=action;
this.SetResourceReference(ContentProperty, resourceKey);
}
public void DoAction ()
{
if (Action!=null)
{
Action();
}
}
public delegate void ClickAction ();
private ClickAction Action;
}

Can't create dependency property in a UserControl in a Windows Runtime Component library

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

Coercion in Silverlight does not work

I've a custom control look like this:
generic.xaml
<Style TargetType="controls:MyControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:MyControl">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="20" />
<RowDefinition Height="20" />
</Grid.RowDefinitions>
<TextBox Grid.Row="0"
Text="{Binding ElementName=slider, Path=Value}" />
<Slider Grid.Row="1" Name="slider" Width="120"
Minimum="1" Maximum="12"
Value="{Binding Mode=TwoWay,
RelativeSource={RelativeSource TemplatedParent},
Path=Value}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
MyControl.cs
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value",
typeof(double),
typeof(MyControl),
new PropertyMetadata(0d, OnValueChanged));
public double Value
{
get { return (double)base.GetValue(ValueProperty); }
set { base.SetValue(ValueProperty, value); }
}
private static void OnValueChanged(DependencyObject source,
DependencyPropertyChangedEventArgs e)
{
MyControl myControl = (MyControl)source;
myControl.OnValueChanged((double)e.OldValue, (double)e.NewValue);
}
protected virtual void OnValueChanged(double oldValue, double newValue)
{
double coercedValue = CoerceValue(newValue);
if (coercedValue != newValue)
{
this.Value = coercedValue;
}
}
private double CoerceValue(double value)
{
double limit = 7;
if (value > limit)
{
return limit;
}
return value;
}
The TextBox is just a dummy to show the value.
Now when I add this control to an Application, I am able to set the Slider value greater than 7, although the value of my DependencyProperty is set to 7.
What I am doing wrong? Does the TwoWayBinding does not work in this situation?
Thanks in advance
Steps for my repro:-
Create a fresh new Silverlight Application in VS2010 call SilverlightApplication1.
Add new "Silverlight Templated Control" to the silverlight project, naming it "MyControl".
Copied the inner contents or you ControlTemplate into the ControlTemplate of the themes/Generic.xaml file. This Entire generic file looks like:-
<Style TargetType="local:MyControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:MyControl">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="20" />
<RowDefinition Height="20" />
</Grid.RowDefinitions>
<TextBox Grid.Row="0"
Text="{Binding ElementName=slider, Path=Value}" />
<Slider Grid.Row="1" Name="slider" Width="120"
Minimum="1" Maximum="12"
Value="{Binding Mode=TwoWay,
RelativeSource={RelativeSource TemplatedParent},
Path=Value}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Copied your C# placed in in MyControl.cs. The whole file looks like:-
using System.Windows;
using System.Windows.Controls;
namespace SilverlightApplication1
{
public class MyControl : Control
{
public MyControl()
{
this.DefaultStyleKey = typeof(MyControl);
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value",
typeof(double),
typeof(MyControl),
new PropertyMetadata(0d, OnValueChanged));
public double Value
{
get { return (double)base.GetValue(ValueProperty); }
set { base.SetValue(ValueProperty, value); }
}
private static void OnValueChanged(DependencyObject source,
DependencyPropertyChangedEventArgs e)
{
MyControl myControl = (MyControl)source;
myControl.OnValueChanged((double)e.OldValue, (double)e.NewValue);
}
protected virtual void OnValueChanged(double oldValue, double newValue)
{
double coercedValue = CoerceValue(newValue);
if (coercedValue != newValue)
{
this.Value = coercedValue;
}
}
private double CoerceValue(double value)
{
double limit = 7;
if (value > limit)
{
return limit;
}
return value;
}
}
}
Added an instance of MyControl to MainPage.xaml, which now looks like:-
<UserControl x:Class="SilverlightApplication1.MainPage"
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:SilverlightApplication1"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<local:MyControl />
</Grid>
</UserControl>
Run the solution, works fine.

WPF custom control problem

I have a problem, and I have not found the solution yet. I woud like to create a base custom control and use it in another custom control. The base control works fine when I use it in a window, but when I use it in the other custom control, the binding does not work.
What's wrong with my code?
Code:
Model:
public class ElementModel
{
public string Name { get; set; }
public string FullName { get; set; }
}
The base control:
public class ListControl : Control
{
static ListControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ListControl), new FrameworkPropertyMetadata(typeof(ListControl)));
}
public ListControl()
{
SetValue(ElementListProperty, new List<ElementModel>());
}
public static readonly DependencyProperty ElementListProperty =
DependencyProperty.Register(
"ElementList",
typeof(List<ElementModel>),
typeof(ListControl),
new FrameworkPropertyMetadata(new List<ElementModel>())
);
public List<ElementModel> ElementList
{
get { return (List<ElementModel>)GetValue(ElementListProperty); }
set { SetValue(ElementListProperty, value); }
}
}
The Wrapper Control:
public class ListWrapper : Control
{
static ListWrapper()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ListWrapper), new FrameworkPropertyMetadata(typeof(ListWrapper)));
}
public ListWrapper()
{
SetValue(EMListProperty, new List<ElementModel>());
}
public static readonly DependencyProperty EMListProperty =
DependencyProperty.Register(
"EMList",
typeof(List<ElementModel>),
typeof(ListWrapper),
new FrameworkPropertyMetadata(new List<ElementModel>())
);
public List<ElementModel> EMList
{
get { return (List<ElementModel>)GetValue(EMListProperty); }
set { SetValue(EMListProperty, value); }
}
}
File Generic.xaml:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:UIControl">
<Style TargetType="{x:Type local:ListControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:ListControl}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ListBox ItemsSource="{TemplateBinding ElementList}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<Label Content="Name:"/>
<TextBlock Text="{Binding Path=Name}" />
<Label Content="Full name:"/>
<TextBlock Text="{Binding Path=FullName}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type local:ListWrapper}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:ListWrapper}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<local:ListControl ElementList="{TemplateBinding EMList}" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
If I put the controls in the window and binding properties, than the ListControl works fine and shows the elements, but the WrapperList does not.
<Window x:Class="MainApplication.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ui="clr-namespace:UIControl;assembly=UIControl"
Title="Window1" Height="304" Width="628">
<Grid>
<ui:ListControl x:Name="listCtr" ElementList="{Binding Path=EList}" HorizontalAlignment="Left" Width="300" />
<ui:ListWrapper x:Name="listWrp" EMList="{Binding Path=EList}" HorizontalAlignment="Right" Width="300" Background="Gray"/>
</Grid>
And the test data injection:
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
DataContext = this;
}
List<ElementModel> elist = null;
public List<ElementModel> EList
{
get
{
if (elist == null)
{
elist = new List<ElementModel>();
ElementModel em = new ElementModel() { Name = "Apple", FullName = "Red Apple" };
elist.Add(em);
em = new ElementModel() { Name = "Pineapple", FullName = "Yellow Pineapple" };
elist.Add(em);
}
return elist;
}
}
}
Project archive
I don’t know why, but if I should wrap this list of element (List) into new collection type (example ElementCollection : ObservalbeCollection) and use this collection type in the dependency property, it works fine...
public static readonly DependencyProperty EMListProperty =
DependencyProperty.Register(
"EMList",
typeof(ElementCollection),
typeof(ListWrapper),
new FrameworkPropertyMetadata(new ElementCollection())
);
public ElementCollection EMList
{
get { return (ElementCollection)GetValue(EMListProperty); }
set { SetValue(EMListProperty, value); }
}
I couldn't find anywhere where you are setting the binding context:
http://msdn.microsoft.com/en-us/library/ms752347.aspx

Categories

Resources