I have some issues with my DependencyProperty in a custom UserControl.
I need to display informations about people in a particular way. To achieve this, I have several UserControls that receive a List<PeopleList> which contains (obviously) one or more People.
Let me show you my (simplified) code and I'll then explain to you the actual behavior of my app.
Here is my UserControl :
public abstract class PeopleLine : UserControl
{
public static readonly DependencyProperty PeopleListProperty =
DependencyProperty.Register("PeopleList", typeof(List<PeopleModel>), typeof(PeopleLine), new PropertyMetadata(default(List<PeopleModel>)));
public List<PeopleModel> PeopleList
{
get { return (List<PeopleModel>)GetValue(PeopleListProperty); }
set { SetValue(PeopleListProperty, value); }
}
}
Then my xaml :
<local:PeopleLine
x:Class="MyApp.Controls.EventSheet.OnePeople"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MyApp.Controls.EventSheet"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid
Margin="0 5"
VerticalAlignment="Top"
Height="51">
<TextBlock
Grid.Column="1"
HorizontalAlignment="Center"
Foreground="Red"
FontSize="25"
Text="{Binding PeopleList[0].Name}"/>
</Grid>
</local:PeopleLine>
And this all starts with my Page which contains an ItemsControl with a correct ItemsSource (I already checked it) and an ItemTemplateSelector (also working perfectly). Here is one of the DataTemplate used by the selector :
<DataTemplate x:Key="OnePeople">
<peoplecontrols:OnePeople
PeopleList="{Binding LinePeopleList}"/>
</DataTemplate>
I'm using several Models That are not really important here since I simplified my code to only have the most important information.
So, back to my issue. When replacing the peoplecontrols:OnePeople in the selector's DataTemplate by a string and putting LinePeopleList[0].Nameas Text, I have the correct text displayed, proving me that my data is correct at this point.
Problem is that when putting back my peoplecontrols:OnePeople, my DependencyProperty is never set. I put a breakpoint at PeopleList's setter and it never triggers.
I tried several modifications (especially those that are given in this post, so replacing the typeof(List<PeopleModel>)by typeof(object) has already been tried) with no success. Also, I tried to replace my DependencyProperty to a string and directly send the name in the DataTemplate but the setter is still not called...
I have no more ideas now and don't understand what's wrong with my code. Any help would be greatly appreciated.
Thanks in advance.
Thomas
Try adding the following line in your UserControl's Constructor, after the call to InitializeComponent:
(this.Content as FrameworkElement).DataContext = this;
I created a sample app on regarding this. Hopefully it reflects your situation correctly:
https://github.com/mikoskinen/uwpusercontrollistdp
If you clone the app and run it, you'll notice that the binding doesn't work. But if you uncomment the Datacontext = this line from UserControl, everything should work OK. Here's working code:
public PeopleLine()
{
this.InitializeComponent();
(this.Content as FrameworkElement).DataContext = this;
}
Related
How do I provide a default value to a binding in a UserControl's XAML, in such a way that Visual Studio will correctly pick up on it?
I'm trying to implement a reusable WPF UserControl, which uses DependencyProperties to customize its behavior, and I'm running into strange behavior in Visual Studio regarding the property's default value.
Take the following control:
Widget.designer.cs
namespace WpfPropertiesTest
{
public partial class Widget : UserControl
{
public Widget()
{
InitializeComponent();
}
public static readonly DependencyProperty TestProperty =
DependencyProperty.Register(nameof(Test), typeof(string), typeof(Widget),
new PropertyMetadata("Hello World"));
public string Test
{
get { return (string)GetValue(TestProperty); }
set { SetValue(TestProperty, value); }
}
}
}
Widget.xaml:
<UserControl x:Class="WpfPropertiesTest.Widget"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="_this">
<TextBlock Text="{Binding ElementName=_this, Path=Test, FallbackValue='Fallback', TargetNullValue='Null', Mode=OneWay}" />
</UserControl>
When I look at the designer of Widget.xaml, I see the fallback value, which is reasonable:
However, lets say I now add a Widget to a window:
// TestWindow.xaml
<Window x:Class="WpfPropertiesTest.TestWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfPropertiesTest"
Title="TestWindow" Height="100" Width="200">
<Grid>
<local:Widget />
</Grid>
</Window>
I would expect to see one of either "Hello World", "Fallback", or "Null", but what I actually get is this:
... Which is the name of the property that I'm binding to.
At runtime, using the same code, I can see the default value just fine:
Now, if I explicitly set a value for the property:
<local:Widget Test="A value that I put in." />
The designer now correctly shows:
All of this tells me that my binding is correct, but the Visual Studio (reasonably) doesn't actually look at the dependency properties in the codebehind. This becomes a problem when I'm actually doing something with the property, such as binding visibility to it.
So, what am I missing? Is there some way to give Visual Studio a value to use in the designer? I don't want to have to explicitly set all of my UserControl properties every time I use it, and I would like to have the control behave in the designer as close to runtime as possible.
Should I forego the binding altogether, and just set the value in the codebehind in the property callback?
In a more general sense, is this the correct approach for making reusable UserControls that can be configured by the consumer?
Solution
If I'm not mistaken the reason for that behavior is that you have project code disabled in your designer. To enable project code toggle the rightmost button in the bottom part of the designer, right to the left from the scroll bar.
Diagnosis
Let's do a simple experiment. Firstly, let's create simple test class:
namespace Test
{
public class EmptyClass { }
}
Then let's put this XAML code in some XAML control with a designer:
<Grid xmlns:test="clr-namespace:Test">
<Grid.Resources>
<ObjectDataProvider x:Key="Provider"
ObjectType="test:EmptyClass"
MethodName="GetType" />
</Grid.Resources>
<TextBlock Text="{Binding Source={StaticResource Provider}}" />
</Grid>
Now in the designer view, when project code is enabled, we see Test.EmptyClass. However, when project code is disabled, we see something along the lines of Mocks.Test_EmptyClass_0_96752088. This leads to a conclusion that the designer uses a generated mock class rather than the actual class (which is what I'd expect - that the designer is not using code from my project).
I don't know the exact mechanics of generating mock classes. Perhaps the static constructor for the mocked class is not called, or the mock class does not even derive from the original class. Either way, your code, which assigns the default property metadata, is not (and should not be) executed.
[Edit]: I figured out how to do this on my own. I posted my solution in the hope that it will save someone else a few days of Googling. If you are a WPF guru, please look at my solution and let me know if there is a better / more elegant / more efficient way to do this. In particular, I am interested in knowing what I don't know... how is this solution going to screw me down the road? The problem really boils down to exposing inner control properties.
Problem:
I am creating some code to auto-generate a data-bound GUI in WPF for an XML file. I have an xsd file that can help me determine the node types, etc. Simple Key/Value elements are easy.
When I parse this element:
<Key>value</Key>
I can create a new 'KeyValueControl' and set the DataContext to this element. The KeyValueControl is defined as a UserControl and just has some simple bindings on it. It works great for any simple XElement.
The XAML inside this control looks like this:
<Label Content={Binding Path=Name} />
<TextBox Text={Binding Path=Value} />
The result is a line that has a label with the element name and a text box with the value that I can edit.
Now, there are times where I need to display lookup values instead of the actual value. I would like to create a 'KeyValueComboBox' similar to the above KeyValueControl but be able to specify (based on information in the file) the ItemsSource, DisplayMemberPath, and ValueMemberPath. The 'DisplayMemberPath' and 'ValueMemberPath' bindings would be the same as the KeyValueControl.
I don't know if a standard user control can handle this, or if I need to inherit from Selector.
The XAML in the control would look something like this:
<Label Content={Binding Path=Name} />
<ComboBox SelectedValue={Binding Path=Value}
ItemsSource={Binding [BOUND TO THE ItemsSource PROPERTY OF THIS CUSTOM CONTROL]
DisplayMemberPath={Binding [BOUND TO THE DisplayMemberPath OF THIS CUSTOM CONTROL]
SelectedValuePath={Binding [BOUND TO THE SelectedValuePath OF THIS CUSTOM CONTROL]/>
In my code, I would then do something like this (assuming that this node is a 'Thing' and needs to display a list of Things so the user can select the ID:
var myBoundComboBox = new KeyValueComboBox();
myBoundComboBox.ItemsSource = getThingsList();
myBoundComboBox.DisplayMemberPath = "ThingName";
myBoundComboBox.ValueMemberPath = "ThingID"
myBoundComboBox.DataContext = thisXElement;
...
myStackPanel.Children.Add(myBoundComboBox)
So my questions are:
1) Should I inherit my KeyValueComboBox from Control or Selector?
2) If I should inherit from Control, how do I expose the inner Combo Box's ItemsSource, DisplayMemberPath, and ValueMemberPath for binding?
3) If I need to inherit from Selector, can someone provide a small example of how I might get started with that? Again, I'm new to WPF so a nice, simple example would really help if that's the road I need to take.
I ended up figuring how how to do this on my own. I'm posting the answer here so that others can see a solution that works, and maybe a WPF guru will come by and show me a better/more elegant way to do this.
So, the answer ended up being #2. Exposing the inner properties turns out to be the right answer. Setting it up is actually pretty easy.. once you know how to do it. There aren't many complete examples of this (that I could find), so hopefully this one will help someone else that runs into this problem.
ComboBoxWithLabel.xaml.cs
The important thing in this file is the use of DependencyProperties. Note that all we're doing right now is just exposing the properties (LabelContent and ItemsSource). The XAML will take care of wiring the internal control's properties to these external properties.
namespace BoundComboBoxExample
{
/// <summary>
/// Interaction logic for ComboBoxWithLabel.xaml
/// </summary>
public partial class ComboBoxWithLabel : UserControl
{
// Declare ItemsSource and Register as an Owner of ComboBox.ItemsSource
// the ComboBoxWithLabel.xaml will bind the ComboBox.ItemsSource to this
// property
public IEnumerable ItemsSource
{
get { return (IEnumerable)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
public static readonly DependencyProperty ItemsSourceProperty =
ComboBox.ItemsSourceProperty.AddOwner(typeof(ComboBoxWithLabel));
// Declare a new LabelContent property that can be bound as well
// The ComboBoxWithLable.xaml will bind the Label's content to this
public string LabelContent
{
get { return (string)GetValue(LabelContentProperty); }
set { SetValue(LabelContentProperty, value); }
}
public static readonly DependencyProperty LabelContentProperty =
DependencyProperty.Register("LabelContent", typeof(string), typeof(ComboBoxWithLabel));
public ComboBoxWithLabel()
{
InitializeComponent();
}
}
}
ComboBoxWithLabel.xaml
The XAML is pretty straightforward, with the exception of the bindings on the Label and the ComboBox ItemsSource. I found that the easiest way to get these bindings right is to declare the properties in the .cs file (as above) and then use the VS2010 designer to setup the binding source from the properties pane. Essentially, this is the only way I know of to bind an inner control's properties to the base control. If there's a better way to do it, please let me know.
<UserControl x:Class="BoundComboBoxExample.ComboBoxWithLabel"
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"
d:DesignHeight="28" d:DesignWidth="453" xmlns:my="clr-namespace:BoundComboBoxExample">
<Grid>
<DockPanel LastChildFill="True">
<!-- This will bind the Content property on the label to the 'LabelContent'
property on this control-->
<Label Content="{Binding Path=LabelContent,
RelativeSource={RelativeSource FindAncestor,
AncestorType=my:ComboBoxWithLabel,
AncestorLevel=1}}"
Width="100"
HorizontalAlignment="Left"/>
<!-- This will bind the ItemsSource of the ComboBox to this
control's ItemsSource property -->
<ComboBox ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType=my:ComboBoxWithLabel,
AncestorLevel=1},
Path=ItemsSource}"></ComboBox>
<!-- you can do the same thing with SelectedValuePath,
DisplayMemberPath, etc, but this illustrates the technique -->
</DockPanel>
</Grid>
</UserControl>
MainWindow.xaml
The XAML to use this is not interesting at all.. which is exactly what I wanted. You can set the ItemsSource and the LabelContent via all the standard WPF techniques.
<Window x:Class="BoundComboBoxExample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="86" Width="464" xmlns:my="clr-namespace:BoundComboBoxExample"
Loaded="Window_Loaded">
<Window.Resources>
<ObjectDataProvider x:Key="LookupValues" />
</Window.Resources>
<Grid>
<my:ComboBoxWithLabel LabelContent="Foo"
ItemsSource="{Binding Source={StaticResource LookupValues}}"
HorizontalAlignment="Left"
Margin="12,12,0,0"
x:Name="comboBoxWithLabel1"
VerticalAlignment="Top"
Height="23"
Width="418" />
</Grid>
</Window>
For Completeness Sake, here is the MainWindow.xaml.cs
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
((ObjectDataProvider)FindResource("LookupValues")).ObjectInstance =
(from i in Enumerable.Range(0, 5)
select string.Format("Bar {0}", i)).ToArray();
}
}
I tried your solution but it fails for me. It does not pass the value over to inner control at all. What I did is declaration of same dependency properties in outer control and bound inner to outer like that:
// Declare IsReadOnly property and Register as an Owner of TimePicker (base InputBase).IsReadOnly the TimePickerEx.xaml will bind the TimePicker.IsReadOnly to this property
// does not work: public static readonly DependencyProperty IsReadOnlyProperty = InputBase.IsReadOnlyProperty.AddOwner(typeof(TimePickerEx));
public static readonly DependencyProperty IsReadOnlyProperty = DependencyProperty.Register("IsReadOnly", typeof (bool), typeof (TimePickerEx), new PropertyMetadata(default(bool)));
public bool IsReadOnly
{
get { return (bool) GetValue(IsReadOnlyProperty); }
set { SetValue(IsReadOnlyProperty, value); }
}
Than in xaml:
<UserControl x:Class="CBRControls.TimePickerEx" x:Name="TimePickerExControl"
...
>
<xctk:TimePicker x:Name="Picker"
IsReadOnly="{Binding ElementName=TimePickerExControl, Path=IsReadOnly}"
...
/>
</UserControl>
I've been playing around with WPF and MVVM and noticed a strange thing. When using {Binding ElementName=...} on a custom user control, the name of the root element within the user control seems to be visible in the window using the control. Say, here is an example user control:
<UserControl x:Class="TryWPF.EmployeeControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TryWPF"
Name="root">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding}"/>
<Button Grid.Column="1" Content="Delete"
Command="{Binding DeleteEmployee, ElementName=root}"
CommandParameter="{Binding}"/>
</Grid>
</UserControl>
Looks pretty legit to me. Now, the dependency property DeleteEmployee is defined in the code-behind, like this:
public partial class EmployeeControl : UserControl
{
public static DependencyProperty DeleteEmployeeProperty
= DependencyProperty.Register("DeleteEmployee",
typeof(ICommand),
typeof(EmployeeControl));
public EmployeeControl()
{
InitializeComponent();
}
public ICommand DeleteEmployee
{
get
{
return (ICommand)GetValue(DeleteEmployeeProperty);
}
set
{
SetValue(DeleteEmployeeProperty, value);
}
}
}
Nothing mysterious here. Then, the window using the control looks like this:
<Window x:Class="TryWPF.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TryWPF"
Name="root"
Title="Try WPF!" Height="350" Width="525">
<StackPanel>
<ListBox ItemsSource="{Binding Employees}" HorizontalContentAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<local:EmployeeControl
HorizontalAlignment="Stretch"
DeleteEmployee="{Binding DataContext.DeleteEmployee, ElementName=root}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</Window>
Again, nothing fancy... except the fact that both the window and the user control have the same name! But I'd expect root to mean the same thing throughout the whole window XAML file, and therefore refer to the window, not to the user control. Alas, the following message is printed when I run it:
System.Windows.Data Error: 40 : BindingExpression path error:
'DeleteEmployee' property not found on 'object' ''String'
(HashCode=-843597893)'.
BindingExpression:Path=DataContext.DeleteEmployee;
DataItem='EmployeeControl' (Name='root'); target element is
'EmployeeControl' (Name='root'); target property is 'DeleteEmployee'
(type 'ICommand')
DataItem='EmployeeControl' (Name='root') makes me think that it treats ElementName=root as referring to the control itself. The fact that it looks for DeleteEmployee on string confirms that suspicion because string is exactly what the data context is in my contrived VM. Here it is, for the sake of completeness:
class ViewModel
{
public ObservableCollection<string> Employees { get; private set; }
public ICommand DeleteEmployee { get; private set; }
public ViewModel()
{
Employees = new ObservableCollection<string>();
Employees.Add("e1");
Employees.Add("e2");
Employees.Add("e3");
DeleteEmployee = new DelegateCommand<string>(OnDeleteEmployee);
}
private void OnDeleteEmployee(string employee)
{
Employees.Remove(employee);
}
}
It is instantiated and assigned to the window in the constructor, which is the only thing in code-behind for the window:
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel();
}
This phenomenon prompts the following questions:
Is this by design?
If so, how is someone using a custom control supposed to know what name it uses internally?
If Name is not supposed to be used in custom control at all?
If so, then what are the alternatives? I switched to using {RelativeSource} in FindAncestor mode, which is working fine, but are there better ways?
Does this have anything to do with the fact that data templates define their own names copes? It doesn't stop me from referring to the main window from within a template if I just rename it so the name doesn't clash with the control.
Your confusion here about how wpf namescopes work is understanable in this situation.
Your issue is simply that you are applying a binding upon a UserControl, which is the "root" (so to speak) of its own namescope. UserControls, and pretty much any container objects, have their own namescopes. These scopes encompass not only child elements, but the object that contains the namescope as well. This is why you can apply x:Name="root" to your window and (except in this one case) locate it from a child control. If you couldn't, namescopes would be pretty much useless.
The confusion comes when you're acting upon a root of a namescope within an encompassing namescope. Your assumption was that the parent's namescope had precedence, but it does not. The Binding is calling FindName on the target object, which in your case is your user control. (Side note, the Binding isn't doing jack, the actual calls can be found in ElementObjectRef.GetObject, but that's where the Binding delegates the call to)
When you call FindName on the root of a namescope, only names defined within this scope are examined. Parent scopes are not searched. (Edit... a bit more reading of the source http://referencesource.microsoft.com/#PresentationFramework/src/Framework/MS/Internal/Data/ObjectRef.cs,5a01adbbb94284c0 starting at line 46 I see that the algorithm walks up the visual tree until it finds a target, so child scopes have precedence over parent scopes)
The result of all this is that you get the user control instance instead of the window, like you were hoping. Now, to answer your individual questions...
1. Is this by design?
Yep. Otherwise namescopes wouldn't work.
2. If so, how is someone using a custom control supposed to know what name it uses internally?
Ideally, you wouldn't. Just like you don't ever want to have to know the name of the root of a TextBox. Interestingly, though, knowing the names of templates defined within a control is often important when attempting to modify it's look and feel...
3. If Name is not supposed to be used in custom control at all?
If so, then what are the alternatives? I switched to using {RelativeSource} in FindAncestor mode, which is working fine, but are there better ways?
No! It's fine. Use it. If you aren't sharing your UserControl with other people, just make sure to change its name if you are experiencing this particular problem. If you aren't having any problem, reuse the same name all day, it isn't hurting anything.
If you ARE sharing your UserControl, you should probably rename it to something that won't conflict with other people's names. Call it MuhUserControlTypeName_MuhRoot_Durr or something.
4. If so, then what are the alternatives? I switched to using {RelativeSource} in FindAncestor mode, which is working fine, but are there better ways?
Nah. Just change the x:Name of your user control and move on.
5. Does this have anything to do with the fact that data templates define their own names copes? It doesn't stop me from referring to the main window from within a template if I just rename it so the name doesn't clash with the control.
No, I don't believe so. I don't think there is any good reason for it to be, anyhow.
I have a ListBox in WPF where I set ItemsSource Property in Code to a List of "List"
When i now run the Program, i get a List with my classname with as much entrys as the List contains. Thats correct.
Now i secify the following Datatemplate:
<DataTemplate>
<NetworkEditor:NetworkEditor DisplayNetwork="{Binding}"></NetworkEditor:NetworkEditor>
</DataTemplate>
But to the DependencyPropery "DisplayNetwork" is always passed "null" (I tested this with a DebugValueConverter).
Any Ideas?
Xaml of the List Box:
<ListBox Name="myLst" Grid.Row="3" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" >
<ListBox.ItemTemplate>
<DataTemplate>
<NetworkEditor:NetworkEditor DisplayNetwork="{Binding}"></NetworkEditor:NetworkEditor>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Implementaion of the Property in my UserControl:
public Network DisplayNetwork
{
get { return (Network)GetValue(DisplayNetworkProperty); }
set { SetValue(DisplayNetworkProperty, value); }
}
// Using a DependencyProperty as the backing store for DisplayNetwork. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DisplayNetworkProperty =
DependencyProperty.Register("DisplayNetwork", typeof(Network), typeof(NetworkEditor), new FrameworkPropertyMetadata(null, OnDisplayNetworkChanged, CoerceValueCallback));
private static Object CoerceValueCallback(DependencyObject d,Object baseValue)
{
return baseValue;
}
OnDisplayNetworkChanged is never called, because null is always set as Value!
Data Source of my ListBox:
myLst.ItemsSource = ((S7FunctionBlock) myBlock).Networks;
where Networks is a List, and when I debug this Line, it contains data!
Have you checked your NetworkEditor:NetworkEditor class, if you set the DataContext there in. It is an often made mistake to set the DataContext from within a class and then to try accessing the DataContext from Xaml on this tag, thinking that the parents DataContext will be returned.
For checking this, try to change your XAML to the following.
<DataTemplate>
<Grid>
<NetworkEditor:NetworkEditor DisplayNetwork="{Path=DataContext,RelativeSource={RelativeSource,Mode=FindAncestor,AncestorType=Grid}}">
</NetworkEditor:NetworkEditor>
</Grid>
</DataTemplate>
Make a comment if there is an error in, I have not tested it. However, as also Will Dean says, in this case changing the NetworkEditor would be a good idea, if it is under your control.
As HCL says, the DataContext of that control is probably not what you think it is.
To diagnose this, you could change {Binding} to {Binding SomethingThatDoesntExist}, then turn on binding warnings in VS. The binding warning message will tell you which type of object was checked for 'SomethingThatDoesntExist' - you'll probably find it's not what you expected.
If it does turn out to be that NetworkEditor is setting its DataContext to something different to what you think, then a good solution to this problem (provided NetworkEditor is under your control), is to change to setting DataContext on the first object within NetworkEditor (often a Grid in a typical UserControl), rather than on the NetworkEditor object itself.
I found something about this issue for ASP, but it didn't help me much ...
What I'd like to do is the following: I want to create a user control that has a collection as property and buttons to navigate through this collection. I want to be able to bind this user control to a collection and display different controls on it (containing data from that collection).
Like what you had in MS Access on the lower edge of a form ...
to be more precise:
When I actually use the control in my application (after I created it), I want to be able to add multiple controls to it (textboxes, labels etc) between the <myControly> and </mycontrol>
If I do that now, the controls on my user control disappear.
Here is an example of one way to do what you want:
First, the code - UserControl1.xaml.cs
public partial class UserControl1 : UserControl
{
public static readonly DependencyProperty MyContentProperty =
DependencyProperty.Register("MyContent", typeof(object), typeof(UserControl1));
public UserControl1()
{
InitializeComponent();
}
public object MyContent
{
get { return GetValue(MyContentProperty); }
set { SetValue(MyContentProperty, value); }
}
}
And the user control's XAML - UserControl1.xaml
<UserControl x:Class="InCtrl.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="300" Name="MyCtrl">
<StackPanel>
<Button Content="Up"/>
<ContentPresenter Content="{Binding ElementName=MyCtrl, Path=MyContent}"/>
<Button Content="Down"/>
</StackPanel>
</UserControl>
And finally, the xaml to use our wonderful new control:
<Window x:Class="InCtrl.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:me="clr-namespace:InCtrl"
Title="Window1" Height="300" Width="300">
<Grid>
<me:UserControl1>
<me:UserControl1.MyContent>
<Button Content="Middle"/>
</me:UserControl1.MyContent>
</me:UserControl1>
</Grid>
</Window>
I'm having a hard time understanding your question, but I think what you're describing is an ItemsControl using DataTemplates to display the contents of (presumably) an ObservableCollection(T).
A UserControl may not be the best way to do this. You're wanting to add decorations around content, which is basically what Border does: it has a child element, and it adds its own stuff around the edges.
Look into the Decorator class, which Border descends from. If you make your own Border descendant, you should be easily able to do what you want. However, I believe this would require writing code, not XAML.
You might still want to make a UserControl to wrap the buttons at the bottom, just so you can use the visual designer for part of the process. But Decorator would be a good way to glue the pieces together and allow for user-definable content.
Here's a link to a built-in control (HeaderedContentControl) that does the same thing as the accepted answer except that it is an existing control in WPF since .Net 3.0