My WPF App attaches a custom inherited dependency property (from a behavior) to my main application view. The idea is to pass this property (which never changes once the app is running) all the way down to some very nested controls that need it
<Window x:Class="MyApp.Views.MainWindow"
core:SystemBehavior.SystemService="{Binding MySystem}"
It works well. So far, all of my controls have been able to access this data
<ComboBox ItemsSource="{Binding RelativeSource={RelativeSource Self},
Path=(core:SystemBehavior.SystemService).Units}"
But there's this ominous sentence in the MS documentation about Property Value Inheritance that gives me pause.
However, property value inheritance can bridge this gap in the logical
tree and can still pass inherited values through, so long as the
inheritable property was registered as an attached property and no
deliberate inheritance-blocking boundary (such as a Frame) is
encountered.
(emphasis added by me)
So my question is: What elements (besides a frame) can "block" dependency property inheritance?
I can't find any documentation that explicitly answers the question.
I searched referencesource.microsoft.com to come up with this list:
Frame
Page
DocumentReference
FixedPage
PageContent
Related
There is an ItemsControl named Items in the view and a ViewModel contains a BindableCollection<T> property Items property, I want them get binding correctly by using the naming conventions mechanism in caliburn.micro, however it dose not works as expected.
When I add ItemsSource="{Binding Items}" in the view explicitly, it works, I am wondering what's the key point missed when using naming conventions in the ItemsControl?
Firstly, using the word "Items" as a name for a property, control etc is a bad choice. It's confusing. This is true if someone is maintaining your code or reading a question. You should have considered names for things.
The conventions for caliburn micro are explained here:
https://caliburnmicro.com/documentation/conventions
Essentially, a control is examined.
The name is used to look up a property from the datacontext.
If they match then a dependency property of that control will be bound.
Which dependency property is used varies from control to control. Text is the default for TextBox and TextBlock. ItemsSource is the default for an itemscontrol.
Hence the answer to your question is your control name should match the property name.
As they seem to, this is not why your binding is failing.
You also need to provide an instance of that datacontext somehow.
You proved that is happening with your working explicit binding.
The two most likely possible causes are therefore:
Your bootstrapper isn't running the caliburn micro wireup code.
or
Your view isn't provided by the bootstrapper and you've not used viewmodel.bind on it to wire everything up.
or
You've somehow interfered with the default binding conventions.
PS
https://caliburnmicro.com/announcements/stepping-away
I am new to WPF. I'm trying to build an application which has a function (call it Initialisation) where a user has to fill in a lot of data and some parts of the form are repeated. We're rewriting a legacy app that has quite a long wizard in although we will probably use collapsible panels in one window rather than next/previous pages. Also some parts are repeated e.g. the user can specify a number of items, if they say 3 they will need to fill in some configuration info for each, so those controls would need to be repeated three times.
I'm using MVVM and am using this example here: http://msdn.microsoft.com/en-us/magazine/dd419663.aspx
The old wizard had about 4 pages so I'm intending to have one user control (Initialisation) that contains 4 child user controls to break the xaml up a bit.
So far I have the Initialisation (its ViewModel inherits from Workspace ViewModel as in the above example) and it contains one child which is working:
<Expander ExpandDirection="Down" Header="ChildOne">
<view:ChildOne />
</Expander>
I will have separate ViewModels for each child and for Intialisation and this brings me to my problem.
The problem I am having is that ChildOne contains a dropdown which I am trying to bind like so:
<ComboBox x:Name="textMessageTypeCmb" ItemsSource="{Binding Path=TextMessageSelectionOptions, Mode=OneTime}"/>
TextMessageSelectionOptions is a public property in ChildOne's ViewModel. This results in no errors but an empty dropdown - that property getter is never called. If I move that property getter code into the Initialisation's ViewModel instead it works but I'm trying to keep my code in manageable chunks so I'd like to put hat code back in ChildOne's ViewModel. It also works if in my MainWindow I create ChildOne as a workspace instead of Initialisation like this
ChildOneViewModel ws = this.Workspaces.FirstOrDefault(vm => vm is ChildOneViewModel) as ChildOneViewModel;
Can anyone advise whether I am taking the right approach (by dividing it up into several user controls) and what I need to do in the binding to make this work? I don't really understand any of this yet especially binding.
It seems to me that your ChildOne view's DataContext is still this Initialisation vm.
You can bind it the views Datacontext to a ChildOneViewModel object
...
<view:ChildOne DataContext={Binding PropertyReturnsChildOneViewModellObject/>
...
or specify the path for the combobox ItemsSource prop.
<ComboBox x:Name="textMessageTypeCmb" ItemsSource="{Binding Path=PropertyReturnsChildOneViewModellObject.TextMessageSelectionOptions, Mode=OneTime}"/>
Note: PropertyReturnsChildOneViewModellObject is a property of the Initialisation vm.
I am constructing my app infra structure, and finding it hard to achieve a very basic behavior - I want to raise events from different user controls in the system and being able to catch those events on some other user controls that listens to them. For example i have a user control that implements a TreeView. I have another user control that implmements a ListView. Now, i want my ListView to listen to the TreeView, and when the selection is changed on the TreeView, i want to repopulate my ListView accordingly.
I also want this to happen even if the ListView is not located within the TreeView on the WPF logical tree.
PLEASE HELP!!
Thanks,
Oran
Use data binding.
If the content of the list view is stored inside the object shown in the tree view you can just bind into the tree SelectedItem property.
Otherwise bind the tree SelectedItem to a property in your view models (or your window!) and in the setter of this property change the list that is bound to the list view ItemSource property.
You can see the technique in this series on my blog the post I linked to is the last post with the code download link, you'll need to read from the beginning of the series if you want the full explanation.
EDIT: Here's how I did it in one project: (the GridView definition removed since it's not relevant here)
<TreeView
Name="FolderTree"
Width="300"
ItemsSource="{Binding Root.SubFolders}"
ItemTemplate="{StaticResource FolderTemplate}"/>
<ListView
Name="FileView"
ItemsSource="{Binding ElementName=FolderTree, Path=SelectedItem.Files}">
</ListView>
The list bound into the tree view's ItemsSource is of objects that have 3 properties: Name (that is bound to a TextBlock in the FolderTemplate), SubFolders (that is likewise bound to the HierarchicalDataTemplate.ItemsSource property) and Files that is bound to the ListView using {Binding ElementName=FolderTree, Path=SelectedItem.Files}
Note that non of the lists are observable collections (because in this project they never change) but are loaded lazily (on-demand) by the properties getters (because in this project they are expensive to load).
This is the point where the added complexity of MVVM (Model-View-ViewModel pattern) can start to pay off. What you need is a publish/subscribe infrastructure, and MVVM Light has that, along with good MVVM structure that doesn't get overly complex. Prism is another good WPF/Silverlight infrastructure foundation with publish and subscribe support.
I have following questions
Should the consumer of my usercontrol assign the usercontrol's DataContext or set some dependency property. (related to #3 : if DataContext then my individual items need to bind directly to the object given in DC, if DP then I have the luxury to have bind to any VM)
If they set property, and if I am using 3 primitive items, should I accept them as individual properties or combine them together to a Model for my usercontrol
Should I ask the consumer of my usercontrol to send me model or viewmodel ( I say viewmodel but for all the controls I have used so far, I have never seen anybody asking me to send them VM - I am sure some could be implementing MVVM internally
Your consumer wants a user control. So I presume the user control should be able to work in any context/application(WPF). So, to answer your questions
1) The consumer should set dependency properties which is defined in the user control. By using the datacontext you will be coupling the usercontrol to the consumer.
2)Take them as individual primitive properties, otherwise the consumer needs to create an object unnecessarily to cater with your model(coupling again-why should the consumer need to know about your model?).
3)No, you should not ask the cosumer to send you the view model.Why do you need to know which consumer is using your "generic" user control.
If you cannot do any of the above because of practical considerations - then dont worry about breaking any/all the rules because your user conrol is coupled with a specific context-it is not generic any more. If you write a generic user control, any WPF application can use your user control. It is your call.
1.
I would say this depends on the kind of UserControl, if it is "generic" you should be able to change the DataContext as the control internally should not have anything to do with the DataContext. For example if i create an ImageButton UserControl which exposes the properties Caption and ImageSource then those should be bound internally independent of the DataContext, the on the instance those can be bound and the DataContext may be changed as well, e.g.
<uc:ImageButton Caption="{Binding ButtonInfo.Caption}"
ImageSource="{Binding ButtonInfo.Image}"/>
Here one could then change the DataContext to simplify the bindings a bit:
<uc:ImageButton DataContext="{Binding ButtonInfo}"
Caption="{Binding Caption}"
ImageSource="{Binding Image}"/>
If on the other hand the UserControl is a view for a viewmodel i would expect the UserControl to bind to viewmodel properties internally, relative to the DataContext.
So in a DataTemplate where the current DataContext is already the viewmodel of that view a simple instance without anything should do, i.e.
<v:StatisticsView />
If the viewmodel to be passed is in a property of the current DataContext you may bind the DataContext as well:
<v:StatisticsView DataContext="{Binding StatisticsViewModel}"/>
2.
This can be handled either way i would say, especially if you have only three properties its not too much of a hassle to create those. You might want to consider some aspects like dependency, e.g. does it make sense to group all three propeties in an object?
3.
As noted in 1. this should be apparent from the UserControl itself, if it's a StatisticsView the consumer should pass in a StatisticsViewModel (either implicitly by inheriting the current DataContext or by binding it explicitly).
I'm working on a set of controls that has a number of DependencyProperties. The properties are themselves DependencyObjects and created during the get method of the properties. During the Get method, they are also set back to the propertybag using the SetValue() method, so they are in fact valid in Xaml and their properties can be storyboarded without having to explicitly created in the the visual tree.
These DependencyObjects has all its properties as DependencyProperties as well, for supporting DataBinding. They are as mentioned above possible to use in Storyboards.
At the same time I'm developing special designtime support for Blend 3 for these properties and have created an InlineEditorTemplate in the form of a Control. I create the template and set it for the PropertyValueEditor like this:
var vectorEditControl = new FrameworkElementFactory(typeof (VectorEditorControl));
var dataTemplate = new DataTemplate {VisualTree = vectorEditControl};
InlineEditorTemplate = dataTemplate;
In the Control I have the following:
<Grid DataContext="{Binding Value}">
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding Path=X, Mode=TwoWay}"/>
<TextBox Text="{Binding Path=Y, Mode=TwoWay}"/>
<TextBox Text="{Binding Path=Z, Mode=TwoWay}"/>
</StackPanel>
</Grid>
The editor shows up and I can edit the data. And even while debugging, I see that it actually sets the data back to the DependencyProperties on the DependencyObjects, but nothing happens to the Xaml. So the data is actually not persisted in any way in the Xaml and lost when I close the Xaml file and open it again.
Is there anything I need to do specifically for it to actually get into the Xaml? I was under the impression that this would happen automatically?
Excellent Question!
The core issue you're running into a misunderstanding as to what PropertyEditors in Blend/Cider end up databinding to.
Consider this object graph:
- MyControl
-- MyControl.MyProperty
--- FooClass
---- FooClass.BarProperty
Let's look at a scenario where we have a PropertyEditor (of any type: Inline, Dialog or Extended) to property MyControl.MyProperty.
When inside MyPropertyPropertyEditor you'd expect to get a fully settable copy of FooClass and be able to manipulate it's members.
That's a good assumption, but the wrong one.
The core issue is that Blend/Cider have elaborate data structures that represent your model at design time. There's about 3-5 levels of abstraction in how Blend/Cider interact with an actual control.
Creating those levels of abstraction allows Expression Blend / Visual Studio designers to be leveraged between framewroks (Silverlight / WPF) and support advanced scenarios (like Property transactions and property chaining).
So, the value you actually get to DataBind to is just one of those levels of abstraction.
Don't believe me? In your custom PropertyEditor, register for this.DataContextChanged event and checkout the type in this.DataContext. You'll end up getting the PropertyValue class (or one of it's friends).
Every single property change you want persisted to XAML (and shown on the design surface) should go through those abstraction layers.
the question you have to ask yourself is "Where do I get one of these absteaction classes for my PropertyValue.Value property instance?".
Well, what I'd do if I were you is create a ModelItem around MyControl.MyProperty and set that as your PropertyEditor.DataContext.
We've shipped an example of using ModelFactory.CreateItem in the Silverlight Toolkit as part of the Chart DefaultInitializer: Source Code, Ning Zhang (Awesome Design Time Dev) explains about ModelItem
If you've got follow-up questions I'd consider pinging PeteBl or UnniR through the Silverlight Insiders mailing list.
Sincerely,
-- Justin
It partly solves my problem. I'm having a dialog with UnniR for a followup.
I couldn't see how I could use this together with the PropertyValueEditor, but for default values this is brilliant and something I'll implement ASAP.
Thanks.