So I have a UserControl that contains a ListView and a Button. I have included my UserControl in Window1.xaml, but I don't know what do I have to do so I can access my ListView control in Window1.xaml.cs .
What else should I need to do ? What is the best aproach here ?
That is not something you should be doing, instead create properties on the UserControl which the internals are bound to, then you have a clean interface.
e.g.
<UserControl Name="control" ...>
<ListView ItemsSource="{Binding ItemsSource, ElementName=control}">
<!-- ... -->
public class MyUserControl : UserControl
{
public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(MyUserControl), new UIPropertyMetadata(null));
public IEnumerable ItemsSource
{
get { return (IEnumerable)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
}
<Window ...>
<local:MyUserControl x:Name="myUc"/>
<!-- ... -->
myUc.ItemsSource = new string[] { "Lorem", "Ipsum" };
Related
I have a custom UserControl, and I would like to attach custom properties to some contained UI elements.
I tried to achieve it like this, but VS does not accept my XAML code.
It says MyProp is not available, or accessible.
<UserControl
x:Class="mynamespace.MyDataSourceSelector"
xmlns:local="clr-namespace:mynamespace"
... >
<TabControl>
<TabItem Header="Tab1" local:MyDataSourceSelector.MyProp="something1"/>
<TabItem Header="Tab2" local:MyDataSourceSelector.MyProp="something2"/>
</TabControl>
<UserControl>
My custom UserControl class looks something like this:
public partial class MyDataSourceSelector: UserControl
{
...
public string MyProp
{
get { return (string)GetValue(MyPropProperty); }
set { SetValue(MyPropProperty, value); }
}
public static readonly DependencyProperty MyPropProperty
= DependencyProperty.Register(
"MyProp",
typeof(string),
typeof(MyDataSourceSelector),
new PropertyMetadata(null)
);
}
I would like to bind a value for every tab, then read out the active tab's MyProp value, when needed.
How can I do this?
You messed up a few things. In your case you should declaring the extension properties like
public static class TabItemExtensions
{
public static void SetMyProp(TabItem element, string value)
{
element.SetValue(MyPropProperty, value);
}
public static string GetMyProp(TabItem element)
{
return (string)element.GetValue(MyPropProperty);
}
public static readonly DependencyProperty MyPropProperty
= DependencyProperty.RegisterAttached(
"MyProp",
typeof(string),
typeof(TabItemExtensions),
new PropertyMetadata(null)
);
}
and use it like
<TabItem Header="Tab1" local:TabItemExtensions.MyProp="something1"/>
I need to change a value from MainWindow of a Control inside my CustomControl.
So lets say I want to change the Labels Content inside UserControl MyControl from MainWindow.xaml.
Example:
<UserControl x:Class="XXXXX.MyUserControl"
.
.
.
>
<Grid>
<Label x:Name="TestLabel"/>
</Grid>
</UserControl>
And in MainWindow.xaml:
<MyUserControl x:Name="TestControl" />
Now how can I access Label.Content from Xaml Designer in MainWindow.xaml?
I didn't find anything out there, so hopefully someone knows how to do that.
Thanks a lot
Expose a custom Property in your UserControl, like below
public partial class MyUserControl : UserControl
{
public MyUserControl()
{
InitializeComponent();
var dpd = DependencyPropertyDescriptor.FromProperty(LabelContentProperty, typeof(MyUserControl));
dpd.AddValueChanged(this, (sender, args) =>
{
_label.Content = this.LabelContent;
});
}
public static readonly DependencyProperty LabelContentProperty = DependencyProperty.Register("LabelContent", typeof(string), typeof(MyUserControl));
public string LabelContent
{
get
{
return GetValue(LabelContentProperty) as string;
}
set
{
SetValue(LabelContentProperty, value);
}
}
}
In xaml of MainWindow
<MyUserControl x:Name="TestControl" LabelContent="Some Content"/>
Added the Following to your UserControl
<UserControl x:Class="XXXXX.MyUserControl"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
.
.
>
Have the User Control Implement INotifyPropertyChanged
Add a Property to the user control like this
Private _LabelText As String
Public Property LabelText() As String
Get
Return _LabelText
End Get
Set(ByVal value As String)
_LabelText = value
OnPropertyChanged("LabelText")
End Set
End Property
Update the Label to Bind from that Property
<Label x:Name="TestLabel" Content="{Binding Path=LabelText}"/>
Then in your MainWindow you can change the property accourdingly
<MyUserControl x:Name="TestControl" LabelText="Testing" />
Then your code behind can also reference that property
I am factoring some code into UserControls which parameters are bound when consumed. I am meeting difficulties with the use of ObservableCollection as a DependencyProperty.
The example showing the difficulty is a project consisting in a MainWindow with two DependencyProperty:
one representing a String (named "Data") and
another one representing an ObservableCollection (named "Origin");
and a UserControl (named UserControl1) exposing two similar DependencyProperty (named resp. "Liste" and "Noun").
The MainWindow contains a TextBlock which Text is bound to "Data" and a ComboBox which ItemsSource is bound to "Origin". Both are working fine.
Both controls are factored into UserControl1, with the DependencyProperty "Liste" and "Noun" acting as intermediate, and UserControl1 is consumed in MainWindow.
Each DataContext (of MainWindow and of UserControl1) is set to "this".
The trouble is while the factored TextBlock (within UserControl1) is working and showing the content of "Data", the factored ComboBox is not working and its DropDown is empty.
The code of MainWindow.xaml is:
<Window x:Class="ChainedBindingUserControl.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"
xmlns:Local="clr-namespace:ChainedBindingUserControl"
>
<StackPanel>
<TextBlock Text="{Binding Data}"
Width="150"
/>
<ComboBox ItemsSource="{Binding Origin}"
Width="150"
/>
<Label Content="--------------------------------------------------"
Width="200"
/>
<Local:UserControl1 Liste="{Binding Origin}"
Noun="{Binding Data}"
Height="50" Width="150"
/>
</StackPanel>
</Window>
Its code behind is :
namespace ChainedBindingUserControl
{
public partial class MainWindow : Window
{
public ObservableCollection<String> Origin
{
get { return (ObservableCollection<String>)GetValue(OriginProperty); }
set { SetValue(OriginProperty, value); }
}
public static readonly DependencyProperty OriginProperty =
DependencyProperty.Register("Origin", typeof(ObservableCollection<String>), typeof(MainWindow),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender));
public String Data
{
get { return (String)GetValue(DataProperty); }
set { SetValue(DataProperty, value); }
}
public static readonly DependencyProperty DataProperty =
DependencyProperty.Register("Data", typeof(String), typeof(UserControl1),
new FrameworkPropertyMetadata("Blablabla", FrameworkPropertyMetadataOptions.AffectsRender));
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
ObservableCollection<String> zog = new ObservableCollection<String>();
zog.Add("A");
zog.Add("B");
zog.Add("C");
Origin = zog;
}
}
}
The file UserControl1.xaml is :
<UserControl x:Class="ChainedBindingUserControl.UserControl1"
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"
Name="root"
d:DesignHeight="300" d:DesignWidth="300">
<StackPanel>
<TextBlock Text="{Binding Noun}"
/>
<ComboBox ItemsSource="{Binding Liste}"
/>
</StackPanel>
</UserControl>
Its code behind is :
namespace ChainedBindingUserControl
{
public partial class UserControl1 : UserControl
{
public ObservableCollection<String> Liste
{
get { return (ObservableCollection<String>)GetValue(ListeProperty); }
set { SetValue(ListeProperty, value); }
}
public static readonly DependencyProperty ListeProperty =
DependencyProperty.Register("Liste", typeof(ObservableCollection<String>), typeof(UserControl1),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender));
public String Noun
{
get { return (String)GetValue(NounProperty); }
set { SetValue(NounProperty, value); }
}
public static readonly DependencyProperty NounProperty =
DependencyProperty.Register("Noun", typeof(String), typeof(UserControl1),
new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.AffectsRender));
public UserControl1()
{
InitializeComponent();
this.DataContext = this;
}
}
}
`
EDIT
According to the pieces of information and snippets provided on http://sshumakov.com/2012/11/13/how-to-create-dependency-properties-for-collections/ , I changed the code behind of UserControl1 into
public partial class UserControl1 : UserControl
{
public IList Liste
{
get { return (List<String>)GetValue(ListeProperty); }
set { SetValue(ListeProperty, value); }
}
public static readonly DependencyProperty ListeProperty =
DependencyProperty.Register("Liste", typeof(IList), typeof(UserControl1),
new FrameworkPropertyMetadata(new List<String>(), FrameworkPropertyMetadataOptions.AffectsRender));
public String Noun
{
get { return (String)GetValue(NounProperty); }
set { SetValue(NounProperty, value); }
}
public static readonly DependencyProperty NounProperty =
DependencyProperty.Register("Noun", typeof(String), typeof(UserControl1),
new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.AffectsRender));
public UserControl1()
{
InitializeComponent();
this.DataContext = this;
SetValue(ListeProperty, new List<String>());
}
}
but it is still not working.
The trouble doesn't come from the DataContext since the TextBlock works as expected.
The trouble here is specific: why a DependecyProperty acting as an intermediate for Binding is working when the property is of type String while it doesn't work when it is of type ObservableCollection (or List, etc).
Thanks in advance for any explanation.
Your problem is in the UserControl's xaml, here:
<TextBlock Text="{Binding Noun}"
/>
<ComboBox ItemsSource="{Binding Liste}"
/>
These binding expressions are attempting to locate Noun and Liste properties on the DataContext of your UserControl, not on the UserControl itself. You need to specify a different target. Since you've already named your UserControl element, you can replace the bindings with this:
<TextBlock Text="{Binding ElementName=root, Path=Noun}"
/>
<ComboBox ItemsSource="{Binding ElementName=root, Path=Liste}"
/>
Imagine that you are creating control that has property that accepts collection:
public class CustomControl : Control
{
public IEnumerable<string> Items { get; set; }
}
If you want property Items to act as binding target you must change it to be dependency property:
public class CustomControl : Control
{
public static readonly DependencyProperty ItemsProperty =
DependencyProperty.Register("Items", typeof(IEnumerable<string>), typeof (CustomControl), new PropertyMetadata(new List<string>()));
public IEnumerable<string> Items
{
get { return (IEnumerable<string>) GetValue(ItemsProperty); }
set { SetValue(ItemsProperty, value); }
}
}
As you can see, we changed this property to dependency property and supplied new instance of List class as default parameter. As it turned out, this default value will be used on class level (i.e. it will be created only once and each instance of CustomControl will have reference to the same collection). Therefore, we need one modification:
public class CustomControl : Control
{
public CustomControl()
{
Items = new List<string>();
}
}
Now you can use this control and supply value for Items property via binding:
<Grid>
<DependencyPropertiesCollection:CustomControl Items="{Binding ItemsSource}"/>
</Grid>
Currently this control has one limitation – Items property can’t be filled directly in XAML like this code does:
<Grid>
<DependencyPropertiesCollection:CustomControl>
<DependencyPropertiesCollection:CustomControl.Items>
<System:String>Item 1</System:String>
<System:String>Item 2</System:String>
<System:String>Item 3</System:String>
<System:String>Item 4</System:String>
<System:String>Item 5</System:String>
</DependencyPropertiesCollection:CustomControl.Items>
</DependencyPropertiesCollection:CustomControl>
</Grid>
To fix this, you need to change property type from IEnumerable to IList:
public class CustomControl : Control
{
public static readonly DependencyProperty ItemsProperty = DependencyProperty.Register("Items", typeof (IList), typeof (CustomControl), new PropertyMetadata(new List<string>()));
public IList Items
{
get { return (IList)GetValue(ItemsProperty); }
set { SetValue(ItemsProperty, value); }
}
public CustomControl()
{
Items = new List<string>();
}
}
Credits:-
http://sshumakov.com/2012/11/13/how-to-create-dependency-properties-for-collections/
I created a UserControl, which has a property called Hero
public partial class UcHeros : UserControl
{
public UcHeros()
{
InitializeComponent();
Hero = "Spiderman";
}
public static readonly DependencyProperty HeroProperty = DependencyProperty.Register("Hero", typeof(string), typeof(UcHeros), new PropertyMetadata(null));
public string Hero
{
get { return (string)GetValue(HeroProperty); }
set { SetValue(HeroProperty, value); }
}
}
I'm using this UserControl inside a Window like this :
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wpfApplication1="clr-namespace:WpfApplication1"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Title="MainWindow" Height="350" Width="525">
<Grid>
<StackPanel>
<wpfApplication1:UcHeros x:Name="Superhero" />
<Button Click="OnClick">Click</Button>
</StackPanel>
</Grid>
</Window>
Now to get the Hero value I use this :
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public static readonly DependencyProperty HumanProperty = DependencyProperty.Register("Human", typeof(string), typeof(MainWindow), new PropertyMetadata(null));
public string Human
{
get { return (string)GetValue(HumanProperty); }
set { SetValue(HumanProperty, value); }
}
private void OnClick(object sender, RoutedEventArgs e)
{
Debug.WriteLine(Superhero.Hero);
}
}
I can access to the Hero because I gived a name to that UserControl in my XAML declaration x:Name="Superhero", but how can I access to that value if I remove the Name property ?
I mean : How can I store the Hero value in the Human value using some sort of Binding !
Just Bind your Human property to the Hero property on your control:
<wpfApplication1:UcHeros Hero="{Binding Human, Mode=OneWayToSource}" />
Try using a OneWayToSource Binding if you just want to read the value and not update it.
UPDATE >>>
As #Killercam suggested, try setting the default value for your property in the declaration instead of the constructor:
public static readonly DependencyProperty HeroProperty = DependencyProperty.
Register("Hero", typeof(string), typeof(UcHeros),
new PropertyMetadata("Spiderman"));
If that still doesn't work, then you've got something else going on there.
I've made a usercontrol and added a new property like this:
public partial class MyControl : UserControl
{
public static readonly DependencyProperty SelectedBrushProperty;
static MyControl() {
SelectedBrushProperty = DependencyProperty.Register("SelectedBrush",
typeof(Brush),
typeof(MyControl),
new PropertyMetadata(Brushes.AliceBlue));
}
public Brush SelectedBrush {
get {
return (Brush)GetValue(SelectedBrushProperty);
}
set {
SetValue(SelectedBrushProperty,value);
}
}
public MyControl()
{
InitializeComponent();
}
}
My question is:
When in the XAML of my custom control, how can I use it?
You may bind to the property in the XAML of your Control:
<UserControl x:Class="MyNamespace.MyControl" ...>
<Grid>
<Label Background="{Binding SelectedBrush,
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}"/>
</Grid>
</UserControl>
If you set DataContext = this; in the constructor of MyControl, you may omit the RelativeSource of the binding:
<Label Background="{Binding SelectedBrush}"/>
Note that there is no need for the static constructor. You could write this:
public static readonly DependencyProperty SelectedBrushProperty =
DependencyProperty.Register("SelectedBrush", typeof(Brush), typeof(MyControl),
new PropertyMetadata(Brushes.AliceBlue));