Reputation: 281
C#, WPF.
I am trying to implement a UserControl
with elements bound to properties in an object hierarchy. I have been using this as a reference.
I have created the following minimal example. It implements three instances of the UserControl
, with the textbox in each case representing a filename. A dependency property is used to permit binding. Although it executes without errors, the textboxes are blank. They should contain "test1", "test2" and "test3". What am I missing?
Main window:
<Window x:Class="CustomControlTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:mycontrols="clr-namespace:MyControls"
mc:Ignorable="d"
Title="MainWindow" Height="100" Width="800">
<Grid>
<StackPanel Orientation="Vertical" DataContext="{Binding ElementName=parent}">
<mycontrols:DataFileControl x:Name="Ctrl1" FName="{Binding Path=project.File1.Filename}"/>
<mycontrols:DataFileControl x:Name="Ctrl2" FName="{Binding Path=project.File2.Filename}"/>
<mycontrols:DataFileControl x:Name="Ctrl3" FName="{Binding Path=project.File3.Filename}"/>
</StackPanel>
</Grid>
</Window>
namespace CustomControlTest
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
Project project = new Project();
public MainWindow()
{
InitializeComponent();
project.File1.Filename = "test1";
project.File2.Filename = "test2";
project.File3.Filename = "test3";
}
}
public class Project : INotifyPropertyChanged
{
public DataFile File1 { get; set; } = new DataFile();
public DataFile File2 { get; set; } = new DataFile();
public DataFile File3 { get; set; } = new DataFile();
public event PropertyChangedEventHandler PropertyChanged;
}
public class DataFile : INotifyPropertyChanged
{
public string Filename { get; set; } = "";
public event PropertyChangedEventHandler PropertyChanged;
}
}
UserControl:
<UserControl x:Class="MyControls.DataFileControl"
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="40"
d:DesignWidth="800"
Name="TheCtrl">
<Grid Height="20">
<TextBox Name="filenameTextBox" Margin="5,0,5,0" Text="{Binding ElementName=TheCtrl, Path=FName, Mode=TwoWay}"/>
</Grid>
</UserControl>
namespace MyControls
{
public partial class DataFileControl : System.Windows.Controls.UserControl
{
public string FName
{
get { return (string)GetValue(FNameProperty); }
set { SetValue(FNameProperty, value); }
}
public static readonly DependencyProperty FNameProperty =
DependencyProperty.Register("FName", typeof(string), typeof(DataFileControl), new PropertyMetadata(null));
public DataFileControl()
{
InitializeComponent();
}
}
}
Upvotes: 0
Views: 74
Reputation: 128013
The expression
FName="{Binding Path=project.File1.Filename}"
requires a public property named project
in the current DataContext, which you have not set. You should have noticed a data binding error message in the Output Window in Visual Studio when you debug the application.
Change it to
public Project project { get; } = new Project();
public MainWindow()
{
InitializeComponent();
project.File1.Filename = "test1";
project.File2.Filename = "test2";
project.File3.Filename = "test3";
DataContext = this;
}
Alternatively, use the Project
instance as DataContext (and thus make it a view model)
private readonly Project project = new Project();
public MainWindow()
{
InitializeComponent();
project.File1.Filename = "test1";
project.File2.Filename = "test2";
project.File3.Filename = "test3";
DataContext = project;
}
and change the binding expressions to
FName="{Binding File1.Filename}"
Upvotes: 1