in my application I'm using two usercontrol : UserControl1 is the main one, inside it, I have UserControl2 used six times.
UserControl2 has several combobox, and I would like to fill them dynamically from the final application. As a start I'm trying to bind data to one of them.
The combobox in UserControl2 look like this :
<ComboBox x:Name="VidTransform" Template="{DynamicResource BaseComboBoxStyle}" ItemContainerStyle="{DynamicResource BaseComboBoxItemStyle}" Grid.Row="1" ItemsSource="{Binding Path=DataContext.VidTransformsNames,ElementName=Ch_Parameters, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" SelectedValue="{Binding Path=SelectedTransform,ElementName=Ch_Parameters, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
At the moment I'm only able to fill it manually, using this ObservableCollection (all strings shows up correctly) :
private ObservableCollection<string> _VidTransformsNames = new ObservableCollection<string>(new[] { "test0", "test1", "test2", "test3", "test4", "test5" });
public ObservableCollection<string> VidTransformsNames
{
get { return _VidTransformsNames; }
set { _VidTransformsNames = value; }
}
In UserControl1 (which contains UserControl2), I tried to create an other ObservableCollection and fill it dynamically at runtime in my final application.
Here it is :
private ObservableCollection<string> _VideoTransformsNames = new ObservableCollection<string>(new[] { "Test0", "Test1", "Test2", "Test3", "Test4", "Test5" });
public ObservableCollection<string> VideoTransformsNames
{
get { return _VideoTransformsNames; }
set { _VideoTransformsNames = value; }
}
And then binding :
<local:UserControl1 VidTransformsNames="{Binding Path=VideoTransformsNames, ElementName=cmix, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
I'm beginner, but here I'm wrong for sure, as I get this error :
A 'Binding' cannot be set on the 'VidTransformsNames' property of type 'UserControl1'. A 'Binding' can only be set on a DependencyProperty of a DependencyObject.
How can I access and fill up at runtime the observablecollection of UserControl2 if it is nested in UserControl1 ?
This is because your property needs to be declared properly as DependencyProperty
Dependency properties and the WPF property system extend property
functionality by providing a type that backs a property, as an
alternative implementation to the standard pattern of backing the
property with a private field. The name of this type is
DependencyProperty. The other important type that defines the WPF
property system is DependencyObject. DependencyObject defines the base
class that can register and own a dependency property.
Please follow this https://msdn.microsoft.com/library/ms753358(v=vs.100).aspx, or Dependency Property Overview https://msdn.microsoft.com/pl-pl/library/ms752914(v=vs.100).aspx
Example taken from above articles:
public static readonly DependencyProperty IsSpinningProperty =
DependencyProperty.Register(
"IsSpinning", typeof(Boolean),
...
);
public bool IsSpinning
{
get { return (bool)GetValue(IsSpinningProperty); }
set { SetValue(IsSpinningProperty, value); }
}
Let's try to set it to your code:
public static readonly DependencyProperty VideoTransformsNamesProperty =
DependencyProperty.Register("VideoTransformsNames", typeof(ObservableCollection<string>), typeof(UserControl1));
public string VideoTransformsNames
{
get
{
return this.GetValue(VideoTransformsNamesProperty) as ObservableCollection<string>;
}
set
{
this.SetValue(VideoTransformsNamesProperty, value);
}
}
Related
I am creating a Charting application using SciChart.
I have added a chart modifier class which allows editing of the chart data but only the data currently displayed. I need to extend this class so that the full ObservableCollection of each XyDataSeries can be accessed.
I have implemented an attached property which I can bind to in the MainWindow DataContext however whenever I run the application the collection is showing as null in the modifier class. Please can you advise. Thanks
public class MoveBlockModifier : ChartModifierBase
{
public static readonly DependencyProperty XyFGDataProperty = DependencyProperty.RegisterAttached("XyFGData", typeof(ObservableCollection<XyDataSeries<double,double>>), typeof(MoveBlockModifier), new FrameworkPropertyMetadata(new ObservableCollection<XyDataSeries<double,double>>()));
public ObservableCollection<XyDataSeries<double, double>> XyFGData
{
get { return (ObservableCollection < XyDataSeries<double, double>>)GetValue(XyFGDataProperty); }
set { SetValue(XyFGDataProperty, value); }
}
public MoveBlockModifier()
{
_ghostSeries = new FastLineRenderableSeries()
{
Stroke = Colors.Black,
DataSeries = editingSeries,
Name = "GhostSeries",
StrokeThickness = 1,
Opacity = 0.75,
};
}
}
Public Class MainWindow: Window, INotifyPropertyChanged
{
private ObservableCollection<XyDataSeries<double, double>> _xyFGData;
public ObservableCollection<XyDataSeries<double, double>> XYFGData
{
get { return _xyFGData; }
set { _xyFGData = value; OnPropertyChanged("XYFGData"); }
}
}
XAML of MainWindow
<s:SciChartSurface x:Name="Chart2">
<s:SciChartSurface.ChartModifier>
<local:MoveBlockModifier FixStart="{Binding FixStart}" FixEnd="{Binding FixEnd}"
IsEnabled="{Binding ChartTwoMoveBlockEnabled, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
XyFGData="{Binding XYFGData, Mode=TwoWay}" />
</s:ModifierGroup>
</s:SciChartSurface.ChartModifier>
</s:SciChartSurface>
The question above seems incomplete / has some errors. You mention an attached property, which you define as this
public static readonly DependencyProperty XyFGDataProperty = DependencyProperty.RegisterAttached("XyFGData", typeof(ObservableCollection<XyDataSeries<double,double>>), typeof(MoveBlockModifier), new FrameworkPropertyMetadata(new ObservableCollection<XyDataSeries<double,double>>()));
public ObservableCollection<XyDataSeries<double, double>> XyFGData
{
get { return (ObservableCollection < XyDataSeries<double, double>>)GetValue(XyFGDataProperty); }
set { SetValue(XyFGDataProperty, value); }
}
...
but this isn't the way to define attached properties in WPF. Follow the MSDN documentation for how to register an attached property.
Secondly, you define a default value of new ObservableCollectionXyDataSeries<double, double> in your FrameworkPropertyMetadata, but this is a bad idea, because you will share one instance of ObservableCollectionXyDataSeries<double, double> statically across all instances of MoveBlockModifier. Have a look at Where to initialize reference type dependency properties for a custom control?
Lastly its an attached property that you want to define but in XAML you are not using it like an attached property.
This part:
is incorrect. See how an attached property is attached in XAML here.
Finally you bind MoveBlockModifier.XyFGData to a property XYFGData in your main window but the DataContext of the MoveBlockModifier might not be MainWindow.
I suggest starting again and fixing these errors!
I am currently trying to get a view to update when a dependency value changes.
I have copied the code from the view into it's parent and didn't use the dependency and it worked fine. I believe my issue is with how I am creating the DependencyProperty.
public partial class CULabelConfigControl : UserControl {
private CreditUnion CU { get; set; }
public static readonly DependencyProperty CUProperty = DependencyProperty.Register(
"CU",
typeof(CreditUnion),
typeof(CULabelConfigControl),
new FrameworkPropertyMetadata(null)
);
I currently receive an Error at run time:
"A 'Binding' cannot be set on the 'CU' property of type 'CULabelConfigControl'.
A 'Binding' can only be set on a DependencyProperty of a DependencyObject."
Any point in the right direction would be helpful. And let me know if I need to share any other details.
It should look like this:
public partial class CULabelConfigControl : UserControl
{
public static readonly DependencyProperty CUProperty =
DependencyProperty.Register(
nameof(CU),
typeof(CreditUnion),
typeof(CULabelConfigControl));
public CreditUnion CU
{
get { return (CreditUnion)GetValue(CUProperty); }
set { SetValue(CUProperty, value); }
}
}
In the XAML of your UserControl, you would bind to this property by specifying the UserControl as RelativeSource, e.g.
<Label Content="{Binding CU, RelativeSource={RelativeSource AncestorType=UserControl}}"/>
If you need to get notified in the UserControl class whenever the property value changes, you should register a PropertyChangedCallback:
public static readonly DependencyProperty CUProperty =
DependencyProperty.Register(
nameof(CU),
typeof(CreditUnion),
typeof(CULabelConfigControl),
new PropertyMetadata(CUPropertyChanged));
private static void CUPropertyChanged(
DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
var control = (CULabelConfigControl)obj;
// react on value change here
}
Can someone help me with this question?) In My XAML I have Listbox element. I want to add my user property into it(in my case - ConnectorStyle)
My XAML code:
<ListBox ItemsSource="{Binding Nodes}" ItemsPanel="{StaticResource CanvasItemsPanelTemplate}"
ItemTemplate="{StaticResource NodePictureTemplate}"
ItemContainerStyle="{StaticResource CanvasItemStyle}"
ConnectorStyle="{StaticResource ConnectorLineStyle}"/>
In my Model I have prepared this property:
public partial class MainPage : UserControl
{
public static readonly DependencyProperty ConnectorStyleProperty = DependencyProperty.Register(
"ConnectorStyle", typeof(Style), typeof(NodePicture), null);
public MainPage()
{
InitializeComponent();
}
public Style ConnectorStyle
{
get { return (Style)GetValue(ConnectorStyleProperty); }
set { SetValue(ConnectorStyleProperty, value); }
}
}
But I is a mistake - Cannot resolve ConnectorStyle.
Is there a simple (or a right way ) way of doing this?
There are two ways to do this: Either you can write a subclass for the ListBox that adds the DependencyProperty or you can write an attached property.
In your case you probably want to write a subclass that adds the property. Try something like this:
public class MyListBox : ListBox
{
public static readonly DependencyProperty ConnectorStyleProperty = DependencyProperty.Register(
"ConnectorStyle", typeof(Style), typeof(MyListBox), null);
public Style ConnectorStyle
{
get { return (Style)GetValue(ConnectorStyleProperty); }
set { SetValue(ConnectorStyleProperty, value); }
}
}
This will add a new type of ListBox that you can add in your xaml code. It will have all the same properties as a regular ListBox, but it will also have the ConnectorStyle property.
If you need to respond to changes to the ConnectorStyle property in your listbox then you should change the code for the Dependency Property, but that is outside the scope of this question.
And in XAML it shoul be :
<local:ListBoxEx
ConnectorStyle="{StaticResource ConnectorLineStyle}"/>
Consider the following Xaml
<Grid>
<TextBox>Text</TextBox>
<Button>Content</Button>
</Grid>
It will set the
Text Property of a TextBox (only WPF)
Content Property of a Button
Children Property of a Grid
But how is this specified? How do you specify which Property that goes between the opening and closing tag in Xaml?
Is this set by some metadata in the Dependency Property or what?
Thanks
There is a ContentPropertyAttribute that is applied to a class. WPF/Silverlight will use reflection to determine which property to use.
If you want to do this with a custom class, you can do it like so:
[ContentProperty("Bar")]
public class Foo : Control
{
public static DependencyProperty BarProperty = DependencyProperty.Register(
"Bar",
typeof(int),
typeof(Foo),
new FrameworkPropertyMetaData(0));
public int Bar
{
get { return (int)GetValue(BarProperty); }
set { SetValue(BarProperty, value); }
}
}
Then you could specify it in XAML like so:
<lcl:Foo>12</lcl:Foo>
Update
Since it is using reflection, you don't really need to do a DependencyProperty. For instance, this will also work:
[ContentProperty("Bar")]
public class Foo : Control
{
public int Bar { get; set; }
}
I’m creating a UserControl for a rich TreeView (one that has context menus for renaming nodes, adding child nodes, etc.). I want to be able to use this control to manage or navigate any hierarchical data structures I will create. I currently have it working for any data structure that implements the following interface (the interface need not actually be implemented, however, only the presence of these members is required):
interface ITreeItem
{
string Header { get; set; }
IEnumerable Children { get; }
}
Then in my UserControl, I use templates to bind my tree to the data structure, like so:
<TextBlock x:Name="HeaderTextBlock" Text="{Binding Path=Header}" />
What I would like to do is define the name of each of these members in my RichTreeView, allowing it to adapt to a range of different data structures, like so:
class MyItem
{
string Name { get; set; }
ObservableCollection<MyItem> Items;
}
<uc:RichTreeView ItemSource={Binding Source={StaticResource MyItemsProvider}}
HeaderProperty="Name" ChildrenProperty="Items" />
Is there any way to expose the Path of a binding inside a UserControl as a public property of that UserControl? Is there some other way to go about solving this problem?
Perhaps this might help:
Create a new Binding when you set the HeaderProperty property on the Header dependency property:
Header property is your normal everyday DependencyProperty:
public string Header
{
get { return (string)GetValue(HeaderProperty); }
set { SetValue(HeaderProperty, value); }
}
public static readonly DependencyProperty HeaderProperty =
DependencyProperty.Register("Header", typeof(string), typeof(ownerclass));
and the property of your HeaderProperty works as follows:
public static readonly DependencyProperty HeaderPropertyProperty =
DependencyProperty.Register("HeaderProperty", typeof(string), typeof(ownerclass), new PropertyMetadata(OnHeaderPropertyChanged));
public string HeaderProperty
{
get { return (string)GetValue(HeaderPropertyProperty); }
set { SetValue(HeaderPropertyProperty, value); }
}
public static void OnHeaderPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
if (args.NewValue != null)
{
ownerclass c = (ownerclass) obj;
Binding b = new Binding();
b.Path = new PropertyPath(args.NewValue.ToString());
c.SetBinding(ownerclass.HeaderProperty, b);
}
}
HeaderProperty is your normal everyday DependencyProperty, with a method that is invoked as soon as the HeaderProperty changes. So when it changes , it creates a binding on the Header which will bind to the path you set in the HeaderProperty. :)