I have a parent object of type Parent and it currently has a null property called Foo of type Child and that Child class has a property of type string called Name.
If the user types into a Text Box for that Name property then I want to automatically create an instance of Child and set it as the Foo property of Parent before finally setting the Name property of the Child object.
If i use:
{Binding parent.foo.name, Mode=TwoWay}
It doesn't create foo and essentially does nothing. Is there any way to achieve what I want without pre-creating all the possible child objects and then removing them if properties haven't been set?
There is no automatic way. You could consider using a pattern like M-V-VM and handling this logic in the ViewModel. You might also possibly get creative with an IValueConverter so that your binding can run custom code when the value is set. But WPF / Silverlight binding will not automatically do this work for you.
Related
I have a custom control in which I created a custom DependencyProperty called TheObject that can contain a generic object.
<comp:MyControl TheObject="{Binding Country}" />
Sometimes, I need to set the TheObject internally (by code, internally to the control).
I did something like this:
this.TheObject = new Country();
But I realized that it is causing the loss of the DataBinding and the control becomes not responding to data changes.
What I really want is that this new object remains attached to the existing DataBinding of the property.
Use SetCurrentValue:
This method is used by a component that programmatically sets the value of one of its own properties without disabling an application's declared use of the property. The SetCurrentValue method changes the effective value of the property, but existing triggers, data bindings, and styles will continue to work.
this.SetCurrentValue(TheObjectProperty, new Country());
I am trying to properly accomplish the following. I have a UserControl (ProgramView). It has a viewmodel (ProgramViewViewModel). ProgramView is consumed as a child control within a Window (ProgramWindow). ProgramWindow has a public property ProgramId, so the consumer of the window can specify the desired Program (data entity) to show. ProgramView has a property ProgramId, as it's primary job is to display this data. ProgramWindow is little more than a wrapper window for this user control.
ProgramViewViewModel also has a property ProgramId. Changes to this property drive out the operation of the view model, which are surfaced out of the view model using other properties, which ProgramView can bind to.
I am trying to hide the operation of the view model from the consumer of the ProgramView and ProgramWindow.
This ProgramId should be bound through all of these layers. Changes to ProgramWindow.ProgramId should flow to ProgramView.ProgramId and then to ProgramViewViewModel.ProgramId. I cannot figure out how to properly implement this.
My current approach is to surface ProgramId in all three classes as a DP. Within the Window, I would imagine ProgramView being instantiated thusly:
<local:ProgramView ProgramId="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:ProgramWindow}}, Path=ProgramId}" />
This appears to actually work. Within ProgramView, I do obtain changed events for the property, and they do appear to have the correct value. FindAncestor seems to operate properly.
How then should I synchronize the ProgramViewViewModel.ProgramId property? I see two ways. One way would be to set a Binding on the ProgramViewViewModel instance itself, to also use FindAncestor, and find the ProgramId on the ProgramViewViewModel This has two downsides. It requires ProgramViewViewModel to surface ProgramId as a dependency property. I'd rather like to avoid this, but it might be acceptable. Either way, I cannot accomplish it in XAML.
<local:View.DataContext>
<local:ProgramViewViewModel
ProgramId="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:ProgramView}}, Path=ProgramId}" />
</local:View.DataContext>
This does not work. It appears that I cannot introduce a binding expression within the instantiation of the instance. FindAncestor reports that it cannot find ProgramView. My theory here is that the instance is outside of the logical tree, and thus cannot traverse to it's parent.
The second option, which makes more sense, is to bind the ProgramView.ProgramId property to "ProgramId" (in the DataContext). I cannot accomplish this because I cannot figure out how to specify a binding expression on a property defined in the code-behind. is required in the XAML, but the type ProgramId exists on is actually . I cannot figure out how to specify this property.
If I manually (in code-behind of ProgramView) create a Binding instance and call SetBinding(ProgramIdProperty, binding), the value no longer flows into the View itself. I believe this is because I just replaced the binding on ProgramView.ProgramId, which was previously set by ProgramWindow. One binding per-property?
My remaining ideas are to provide TWO ProgramId properties in ProgramView. One bound to the DataContext, the other publicly available to be bound by the consumer (ProgramWindow), and then write OnValueChanged handlers that synchronize the two. This feels like a hack. The other is to manually watch for changes on ProgramView.ProgramId and ProgramView.DataContext within the code-behind of ProgramView, and propagate the value myself. Neither of these ideas feel ideal.
I'm looking for other suggestions.
Your description seems detailed but I'm having trouble understanding why you need to implement this design. I can't help but think DRY.
If you need to expose a dependency property in two such-related view models, I would suggest that you make the child view model (for the user control view) a property of the first (for the program window view). Something like:
public class MainViewModel : ViewModelBase
{
public ProgramViewModel ChildViewModel { get; private set; }
}
public class ProgramViewModel : ViewModelBase
{
private int _ProgramId;
public int ProgramId
{
get { return _ProgramId; }
set
{
if (value != _ProgramId)
{
// set and raise propery changed notification
}
}
}
}
The MainView can get the property using ChildViewModel.ProgramId (data context set to MainViewModel). The ProgramView accesses it by ProgramId (data context set to MainViewModel.ChildViewModel).
I have a static class called commands. One the RoutedCommands in it is called ConfirmNoPrint. I want to Execute it in code behind from my custom control like this:
Commands.ConfirmNoPrint.Execute(null, [WHAT_DO_I_PUT_HERE]);
In the custom control class I have an instance of Binding whose RelativeSource property is set like this:
_mainControlBinding.RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(UserControl), 2);
Can I use one of the properties of _mainControlBinding to get the instance of IInputElement I need to pass as the second parameter of Commands.ConfirmNoPrint.Execute ?
The command binding for ConfirmNoPrint is the parent of my custom control, but it is in a different assembly. I can't add a reference to it since it would cause a circular reference.
I am barking up the wrong tree entirely?
Routed commands are, by definition, routed. If I understand your problem well, you just have to pass this as the second parameter of your command (assuming you're into the control class). The command will be bubbling up the visual tree until it encounters the command binding on the parent.
I'm a bit mystified as to how Attached Properties actually convey their values to either parent or child elements. TextElement.FontFamily causes child elements to inherit the value assigned to that property (a seemingly downstream operation, parent to child). Grid.Column causes a parent item to display that child in a particular position (a seemingly upstream operation, child to parent). How do Attached Property values know to either flow up or down? Is my conception of this incorrect, or is there a piece missing that will put all of this into perspective?
<StackPanel TextElement.FontFamily="Wingdings">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button Grid.Column="1" Content="My Button"/>
</Grid>
</StackPanel>
There are two concepts here: dependency properties and attached dependency properties. "Attached Properties" are dependency properties, and as such support dependency property value inheritance.
About basic dependency properties, a very rough statement would be that they basically inherit their values from parent elements in the wpf (logical/visual) tree. A dependency property (attached or not) inherits its value "downwards" if its metadata is set with the FrameworkPropertyMetadataOptions.Inherit flag, and in many cases this is so.
Attached properties are properties which can be set on any wpf object (basically, at least a DependencyObject) via the DependencyObject.SetValue method. The purpose for this mechanism is to "attach" to other objects information needed by parent objects, not the child objects themselves. For example, the Grid.Row is an attached property required by the Grid to place items within its render area.
Dependency properties are inherited "downwards" automatically by the wpf object system.
Attached properties are examined "upwards" explicitly, in the code of specific objects. In the case of Grid, upon determining where to place its items, it checks for the value of Grid.Row and Grid.Column attached properties on each contained item.
It is also often the technique to create custom attached properties which modify in some way the objects they are attached to (for example, the Drag'n'Drop functionality via attached properties).
As an additional note, a good example of an inheriting attached property is TextElement.FontFamily. Grid.Row and Grid.Column properties do not have the Inherits flag set.
TextElement.FontFamily, from Reflector:
FontFamilyProperty = DependencyProperty.RegisterAttached("FontFamily", typeof(FontFamily), typeof(TextElement), new FrameworkPropertyMetadata(SystemFonts.MessageFontFamily, FrameworkPropertyMetadataOptions.Inherits | FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure), new ValidateValueCallback(TextElement.IsValidFontFamily));
Grid.Row, from Reflector:
RowProperty = DependencyProperty.RegisterAttached("Row", typeof(int), typeof(Grid), new FrameworkPropertyMetadata(0, new PropertyChangedCallback(Grid.OnCellAttachedPropertyChanged)), new ValidateValueCallback(Grid.IsIntValueNotNegative));
From MSDN:
Although attached properties are settable on any object, that does not automatically mean that setting the property will produce a tangible result, or that the value will ever be used by another object. Generally, attached properties are intended so that objects coming from a wide variety of possible class hierarchies or logical relationships can each report common information to the type that defines the attached property. The type that defines the attached property typically follows one of these models:
The type that defines the attached
property is designed so that it can
be the parent element of the elements
that will set values for the attached
property. The type then iterates its
child objects through internal logic
against some object tree structure,
obtains the values, and acts on those
values in some manner.
The type that defines the attached
property will be used as the child
element for a variety of possible
parent elements and content models.
The type that defines the attached
property represents a service. Other
types set values for the attached
property. Then, when the element that
set the property is evaluated in the
context of the service, the attached
property values are obtained through
internal logic of the service class.
An Example of a Parent-Defined Attached Property
The most typical scenario where WPF defines an attached property is when a parent element supports a child element collection, and also implements a behavior where the specifics of the behavior are reported individually for each child element.
DockPanel defines the DockPanel.Dock attached property, and DockPanel has class-level code as part of its rendering logic (specifically, MeasureOverride and ArrangeOverride). A DockPanel instance will always check to see whether any of its immediate child elements have set a value for DockPanel.Dock. If so, those values become input for the rendering logic applied to that particular child element. Nested DockPanel instances each treat their own immediate child element collections, but that behavior is implementation-specific to how DockPanel processes DockPanel.Dock values. It is theoretically possible to have attached properties that influence elements beyond the immediate parent. If the DockPanel.Dock attached property is set on an element that has no DockPanel parent element to act upon it, no error or exception is raised. This simply means that a global property value was set, but it has no current DockPanel parent that could consume the information.
In simple words this is how I understand it (please correct me if I'm wrong).
An object (A) implements a property that will attach to another object (B) (object B doesn't even know about the existence of this "attachable" property). Object B needs to inherit from DependencyObject.
Object A also implements a static method to check for it's "attachable" property in other objects, A.GetAttachedProperty(B).
If B has the attached property from A, A.GetAttachedProperty will read and return it's value. Otherwise A will try to read it, and return null since it's not there.
I have a an object which is set to the DataContext in a Window. I have textboxes in the window which are bound to the properties on the object. There seems to be a delay however before the properties on the object are updated.
<TextBox x:Name="txtPropertyOne" Text="{Binding Path=PropertyOne,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />
If I change the values in a few textboxes then quickly try to access the properties to which they map, sometimes there are changes which aren't reflected in the properties of the object. I thought that was what the PropertyChanged UpdateSourceTrigger was supposed to take care of.
If I change the values in a few
textboxes then quickly try to access
the properties to which they map
I can interpret this statement in two ways:
You're trying to access the values on a background thread. In that case, you may be accessing the properties before the UI thread has had a chance to do its thing.
You're using a separate message on the UI thread to check the values. Bindings are updated at a priority lower than Send and Normal. So if your message is priority Send or Normal it will be processed before any pending binding updates.
If this doesn't answer your question, please clarify what you mean by "quickly trying to access the properties".
The basic rule of WPF Databinding is simple:
The target property must be a
dependency property, and you're
already correct, it's bound to Text
property of TextBox.
The source property can be a CLR
object (other than any derived WPF's
DependencyObject), but the object
must employ or implement its own
INotifyPropertyChanged.
Have you you already implemented INotifyPropertyChanged on your object?