how to link container and its contents? - wpf

i have an object based on ContentControl type and I want to embed custom controls into its content. below is the code.
the problem is that i need MyContainer to have a list of MyControl objects so that it can communicate to them, and each MyControl will need a reference to its MyContainer.
how is this done properly? one way that i see is to declare an attached property on MyControl and set it to the name of the MyContainer object, but this seems redundant because MyCOntrol objects can search the visual tree to find the container. if searching is the right way to do this, where would i place the code that does the search? in MyControl constructor?
thanks for any input
konstantin
public class MyContainer : ContentControl
{
...
}
public class MyConrol : Control
{
...
}
<c:MyContainer>
<Grid>
<c:MyControl />
</Grid>
</c:MyContainer>

You can add property MyControls to MyContainer class, create a template for MyContainer with a list in it (ItemsControl, ListBox or some other list control), put the list itself inside the grid from your sample code, bind the list's ItemsSource to MyControls property.
To get container for the control in XAML, you can use binding with RelativeSource set to FindAncestor.
If you need to find container from code, you should probably do it every time or cache the value on the first use (can controls be moved to another container?). Contructor is not the appropriate place, because first control is created and only then it is put into the tree.
Attached properties are definitely unnecessary.

Related

Share State Between MainWindow and UserControl

I have a WPF application and want to share data between my MainWindow and one or more UserConrols, but for simplicity lets assume I have only one MainWindow.xaml and one UserControl.xaml. From what I've gathered so far, this can be done with Bindings and Properties. So I tried this with no success.
The Object I want to share between the controls looks like this:
SharedObject {
prop string Name;
prop List<Product> Products;
}
Product {
prop string ItemName;
prop double Price;
prop bool Available;
}
So I load the SharedData in the MainWindow and want to be able to edit this in the UserControl, but in TwoWay mode, to get the modified product list updates also in the MainWindow. I also want to access and modify the Name Property of the SharedObject in the UserControl.
How can I achieve this? Is the Property/Binding the way to go? Can this state management also be done in a more elegant way? (in dotnet Core 3.1)
You should set the DataContext of the window to an instance of your view model (SharedObject) and then let the UserControl inherit the DataContext from its parent window (which it does by default).
You can then bind directly to any public property of the view model from the an element in UserControl.

When are the elements of a ContentProperty actually created?

I am creating a custom WPF control that uses the following markup:
<custom:FilterPanel
Grid.Row="1"
FilterTarget="{Binding Path=MyItems}">
<custom:FilterParameter
ParameterName="Name"
TargetProperty="Name" />
<custom:FilterParameter
ParameterName="Date"
TargetProperty="MyDate" />
</custom:FilterPanel>
I've set the ContentProperty for my FilterPanel to FilterParameters, which is obviously a collection of FilterParameter objects that I add items to using the markup above. My question is, when are the elements of a ContentProperty actually processed so that instances are created and items are actually added to the underlying collection?
I'm interested in sharing the data source of the parent control with its children, is there any point in the WPF lifecycle where I can override this behavior and add custom logic to the creation of this collection of FilterParameters?
Assuming your class derives from Panel, then the first point in the Panel's lifecycle where you can see children (i.e. children that are decalred in XAML like your example - not children generated via bindings) is Panel.EndInit(), a virtual method you can override in your derived class. Specifically the chldren created between the BeginInit and EndInit methods.

How can I bind from a user control to an external object in XAML?

I have an image inside a user control that I want to bind it's visibility to a property I have set up in a class object. The dependency properties are set up and working correctly, but I don't know how to set the binding properly on the image.
The user control and class object are in the same namespace. I thought I would need to set the ElementName to the window or the RelativeSource to the class object, but I'm not getting it to work out.
Here's what a dependency property looks like (defined in MigrateUserWizardObject.cs, this inherits from DependencyObject, this resides in the UserAccountMigrator namespace):
public static readonly DependencyProperty DatabaseStepCompletedVisibilityProperty = DependencyProperty.Register("DatabaseStepCompletedVisibility", typeof(Visibility), typeof(MigrateUserWizardObject));
public Visibility DatabaseStepCompletedVisibility
{
get
{
return (Visibility)GetValue(DatabaseStepCompletedVisibilityProperty);
}
set
{
SetValue(DatabaseStepCompletedVisibilityProperty, value);
}
}
Here's an image that I want bound to this dependency property (defined in ProgressUserControl.xaml, this inherits from UserControl, this resides in the UserAccountMigrator namespace as well):
<Image x:Name="DatabaseCompleted" Source="{StaticResource GreenCheckMarkSource}" Visibility="{Binding Path=DatabaseStepCompletedVisibility, UpdateSourceTrigger=PropertyChanged}" Height="20" HorizontalAlignment="Right"></Image>
This is due to the fact that the DataContext of the image is the user control. How can I make this work?
I think you should look into using the Model-View-ViewModel pattern. Instead of setting the DataContext to the UserControl, set it to an instance of another class (ProgressViewModel, for example). This view model would have all the properties you want to bind to (including your DatabaseStepCompletedVisibility property) and makes it much easier. Right now you are wanting to bind some things to the UserControl, some things to another object somewhere else, etc.. and, as you have found, makes it difficult. Here is more information:
http://jmorrill.hjtcentral.com/Home/tabid/428/EntryId/432/MVVM-for-Tarded-Folks-Like-Me-or-MVVM-and-What-it-Means-to-Me.aspx
Without going that approach, you have to have an instance MigrateUserWizardObject to bind to. You can put that instance in your UserControl (if you insist on using it as the DataContext), then you can bind the the property of the MigrateUserWizardObject property of the UserControl. Also, your MigrateUserWizardObject doesn't have to be a dependency object or dependency property to bind to. A better pattern would be to make it a plain c# class that implements the INotifyPropertyChanged interface.

How can I easily expose bindable properties of nested controls from a custom UserControl?

My first question here on the Stack. Forgive me for the bad explanation in advance.
I am working on my first MVVM application (Silverlight). I have a custom user control that contains a ListBox to show navigation items. This control is placed in my main xaml page. I don't know if I need to create a composite view model (my main page view model) with a view model especially for the custom control in it or if there is some way to elevate the ListBox properties that I need to bind to.
Through XAML I don't know how to bind, let's say, the ItemsSource property of the ListBox inside the custom control to my main page viewmodel. Basically, I'm at the point that I am questioning my design decision for trying to bind the custom control through my main page view model.
What I have done so far is create dependency properties for the custom control and try to tunnel those dependency properties down to the ListBox properties. I've achieved success with this method for ItemsSource but am having issues with SelectedItem.
Even if I do get SelectedItem to work, it still feels Wrong. Thanks for any advice in advance.
The UserControl should inherit the DataContext from its parent control, unless you are setting it directly. You can then bind to the properties on your view model from your UserControl.
If you would like to create a ViewModel specifically for the UserControl, you can also do that. You would then expose it as a property on your main ViewModel, and bind to it in the MainPage. Example:
public class MainViewModel
{
public ChildViewModel ChildInfo { get; private set; }
}
And then in the view:
<Grid>
...
<lcl:ChildView DataContext="{Binding ChildInfo}" />
...
</Grid>
Your ChildViewModel would then contain properties like SelectedItem to bind your ListBox to.

Two-way-like binding between a Resource's property and a runtime object property

my problem is the following :
I have defined a TextBox as a child of a ToolBar in a ResourceDictionary (x:Key MyToolbar). When my application loads, it places the ToolBar correctly inside the Window frame, along with its TextBox. So far, so good.
Of course, I'd like that very TextBox to be two-way databound to some objects' properties that are NOT defined in any ResourceDictionary.
More precisely, when the TextBox is all set in the correct window frame, and then, after the “Open” command a certain file is loaded, a Deserializer builds DesignerCanvas object using values from out of that file, in my case it is a string “Token” CLR property of a class that implements INotifyPropertyChanged.
Here some simplified code snippets. I will leave many blanks for clarity’s sake:
Class DesignerCanvas : INotifyPropertyChanged
{
Private string m_token;
Public string Token
{
Get{….
Set{ if (value…)
OnPropertyChanged(“Token”);
}
//notice there is no Constructor other than the default one
}
And on the XAML side I have something like this:
<ToolBar x:Key=”MyToolbar…..
<TextBox …
Now, my two goals are: to have the “static” TextBox resource on my toolbar pick up the values of the DesignerCanvas’ “Token” property as soon as the property changes (i.e. gets a value for the first time, basically), and similarly, and more importantly, I wish to make it possible to have the DesignerCanvas read the values I could put in manually into the TextBox and fill its Token Property with that user-input text (I think I will opt for the TextBox’ LostFocus Event as a trigger for the string value being passed/bound onto the DesignerCanvas’ “Token” Property).
Anyway, I’m not sure how to set up a perfect two-way (or two-way-like) DataBinding between the TextBox' Text property and the DesignerCanvas' Token Property, since we have one static resource (I’m not sure if static is the correct word), and another dynamic runtime object (again not sure if runtime or dynamic are the words).
How do I achieve this? Do I absolutely need to register a “Token”- DependencyProperty in DesignerCanvas? Do I absolutely need to have a XAML for the DesignerCanvas defined somewhere (for example in my Window1.xaml or a dummy s:DesignerCanvas resource along with the TextBox)?
Help appreciated!
Have you tried databinding with your textbox...
<TextBox Text="{Binding Path=Token, Mode=TwoWay}" />
...then when your app loads and places the ToolBar in the window frame, make sure that it also sets the DataContext property of the ToolBar to the instance of your DesignerCanvas class?

Resources