Modify textblock of a UserControl from another UserControl WPF - c#

i have a UserControl that contains a TextBox now i am loading another UserControl that contains a TextBlock .When the button is clicked, I want to assign value entered in TextBox to TextBlock of another control that is loaded. How can i do this ?
Main UserControl
<UserControl x:Class="IntelliVentory.UserControls.CategoryControl"
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"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
mc:Ignorable="d"
d:DesignHeight="670" d:DesignWidth="1100">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<TextBox Grid.Row="0" Name="CategoryNameBox" Width="350" />
<Button Grid.Row="1" Click="AddCategoryFunc">Load Another Control</Button>
<Grid Grid.Row="2" Name="CategoriesWraper"></Grid>
</Grid>
</UserControl>
Another UserControl
<UserControl x:Class="IntelliVentory.UserControlModules.CategoryModule"
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"
xmlns:local="clr-namespace:IntelliVentory.UserControlModules"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<TextBlock Name="CategoryName" FontSize="12" FontWeight="Thin">Category Name Here</TextBlock>
</Grid>
</UserControl>
Main UserControl.cs
Loading another UserControl.
private void AddCategoryFunc(object sender, RoutedEventArgs e)
{
UserControl categoryMod = new CategoryModule();
CategoriesWraper.Children.Add(categoryMod);
}

You want to have something like
categoryMod.CategoryNameValue = categoryControl.CategoryNameValue;
So you need to define two properties, one CategoryNameValue property with which you get the Text value of the TextBox, and one CategoryNameValue property with which you can set the Text property of the TextBlock.
Define this property in the CategoryControl class,
public string CategoryNameValue { get { return CategoryNameBox.Text; }
And this in CategoryModule class,
public string CategoryNameValue { set { CategoryName.Text = value; }
And you can start using them in your code.
You can define them as Dependency Properties instead of plain CLR properties, and then look to use data binding. With data binding both user controls can be bound to the same data model so their values are synced automatically.
Edit:
Turns out you can access a UserControl's child elements from outside as if they are public fields. That is, you can write code like this without having to define new properties
CategoryModule categoryMod = new CategoryModule();
categoryMod.CategoryName.Text = CategoryNameBox.Text;
CategoriesWraper.Children.Add(categoryMod);

Related

WPF TabControl - Add New Tab With Content Template

I am trying to make a demo application to help me understand WPF/MVVM. I have been struggling for 3 days looking at various tutorials and threads. I want to make a tab control with a new tab button (like here) that lets the user create a new tab with specified content template. I create my user control that I want to be the template here:
<UserControl x:Class="MvvmTest.UserControl1"
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"
xmlns:local="clr-namespace:MvvmTest"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<ListView d:ItemsSource="{d:SampleData ItemCount=5}">
<ListView.View>
<GridView>
<GridViewColumn/>
</GridView>
</ListView.View>
</ListView>
</Grid>
</UserControl>
It is just a control with a ListView. So, I want this ListView to be in any new tab that is opened.
Here is my main window with the actual tab control:
<Window x:Class="MvvmTest.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:local="clr-namespace:MvvmTest"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Button Content="New Tab" Margin="703,6,10,401" Click="Button_Click"/>
<TabControl Name= "TabControl1" Margin="0,33,0,-33" Grid.ColumnSpan="2">
</TabControl>
</Grid>
</Window>
In this code-behind, I try to create a new tab programmatically and set the content template to the new control.
private void Button_Click(object sender, RoutedEventArgs e)
{
TabControl1.Items.Add(new TabItem() { ContentTemplate = UserControl1 });
}
This fails. I also tried setting properties in the XAML which also failed. I'm not sure what else to try.
If you're trying to use MVVM, where is your view model? The approach you have so far is not very MVVM because you're using code-behind to add tab items. The MVVM approach would be to bind the ItemSource property of the TabControl to a collection of items and let the view model add the items for you. You also cannot use a UserControl as a ContentTemplate like that without wrapping it in a DataTemplate definition.
The first thing to do is to define some view models:
// MvvmLight (from NuGet) is included for it's INotifyPropertyChanged
// (ViewModelBase) and ICommand (RelayCommand) classes. INotifyPropertyChanged
// is how Binding works between the View and the View Model. You could
// implement these interfaces yourself if you wanted to.
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using System.Collections.ObjectModel;
using System.Windows.Input;
namespace MvvmTest
{
public class MainWindowViewModel : ViewModelBase
{
// store our list of tabs in an ObservableCollection
// so that the UI is notified when tabs are added/removed
public ObservableCollection<TabItemViewModel> Tabs { get; }
= new ObservableCollection<TabItemViewModel>();
// this code gets executed when the button is clicked
public ICommand NewTabCommand
=> new RelayCommand(() => Tabs.Add(new TabItemViewModel()
{ Header = $"Tab {Tabs.Count + 1}"}));
}
public class TabItemViewModel : ViewModelBase
{
// this is the title of the tab, note that the Set() method
// invokes PropertyChanged so the view knows if the
// header changes
public string Header
{
get => _header;
set => Set(ref _header, value);
}
private string _header;
// these are the items that will be shown in the list view
public ObservableCollection<string> Items { get; }
= new ObservableCollection<string>() { "One", "Two", "Three" };
}
}
Then you can fix your XAML so that it refers to the view-models that you defined. This requires defining the DataContext for your MainWindow and binding the elements of MainWindow to properties on the view model:
<Window x:Class="MvvmTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MvvmTest"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<!--Set the DataContent to be an instance of our view-model class -->
<local:MainWindowViewModel/>
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--The Command of the button is bound to the View Model -->
<Button Grid.Row="0" HorizontalAlignment="Right" Width="100"
Content="New Tab"
Command="{Binding NewTabCommand}" />
<!--ItemsSource is bound to the 'Tabs' property on the view-
model, while DisplayMemeberPath tells TabControl
which property on each tab has the tab's name -->
<TabControl Grid.Row="1"
ItemsSource="{Binding Tabs}"
DisplayMemberPath="Header">
<!--Defining the ContentTemplate in XAML when is best.
This template defines how each 'thing' in the Tabs
collection will be presented. -->
<TabControl.ContentTemplate>
<DataTemplate>
<!--The UserControl/Grid were pointless, so I
removed them. ItemsSource of the ListView is
bound to an Items property on each object in
the Tabs collection-->
<ListView ItemsSource="{Binding Items}">
<ListView.View>
<GridView>
<GridViewColumn Header="Some column"/>
</GridView>
</ListView.View>
</ListView>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</Grid>
</Window>
The result is that when you press the button, a new tab gets created and shown

Update the TextBox.Text in Usercontrol from everywhere

I'm facing an issue that seems recurrent and with a lot of solutions but, I apologize, I cannot/not able apply in my case. Let me summarize the topology: I have a main windows (MainWindow) with a grid and, in the bottom cell I put an user control written by me (UC_StatusMonitor) with a textbox inside the user control (LBL_CONN_Message) where I want to update with result of operations (e.g. "Connected to device X", "Impossible to read data from Y", "Missing fields" etc etc). This is basically used to inform the user if something is right or wrong. I understood I have to use Dependancy to solve this issue but my implementation doesn't work (for sure I missed something).
Let me show the code:
MainWindows.xaml
<Window x:Class="LUX.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:local="clr-namespace:LUX"
mc:Ignorable="d"
Title="LUX" Name ="MainForm" Height="600" Width="800" MinHeight="600" MinWidth="800">
<Border Padding="10">
<Grid Name="Main_Grid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="160"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="100"/>
<RowDefinition Height="*"/>
<RowDefinition Height="22"/>
</Grid.RowDefinitions>
<!-- others controls .... -->
<!-- Monitor -->
<StackPanel Name="Stack_Monitor" Grid.Row="2" Grid.Column="1">
<Grid Name="BottomBar" Height="20">
<local:UC_StatusMonitor Height="100" Grid.Row="2" Grid.Column="1"/>
</Grid>
</StackPanel>
</Grid>
</Border>
</Window>
Then the code for the Control
UC_StatusMonitor.xaml
<UserControl x:Class="LUX.UC_StatusMonitor"
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"
xmlns:local="clr-namespace:LUX"
mc:Ignorable="d"
xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
d:DesignHeight="20" d:DesignWidth="300">
<Grid Name="UCR_Base" Background="White">
<WrapPanel>
...
<TextBox Name="LBL_CONN_Message" Margin = "10 0 0 0" VerticalAlignment="Center" IsReadOnly="True" BorderThickness="0" Text="{Binding MyTextProperty, ElementName=control}"/>
...
</WrapPanel>
</Grid>
</UserControl>
UC_StatusMonitor.xaml.cs
namespace LUX {
/// <summary>
/// Interaction logic for StatusMonitor.xaml
/// </summary>
public partial class UC_StatusMonitor : UserControl
{
Button[] MenuButtons;
//// The dependency property which will be accessible on the UserControl
public static readonly DependencyProperty MyTextPropertyProperty = DependencyProperty.Register("MyTextProperty", typeof(string), typeof(UC_StatusMonitor), new UIPropertyMetadata(String.Empty));
public string MyTextProperty
{
get { return (string)GetValue(MyTextPropertyProperty); }
set { SetValue(MyTextPropertyProperty, value); }
So, I'm expecting that, everywhere (in all the classes into the workspace, I declared a status monitor static object), I should use an instruction like
MyTextProperty = "Connected";
and then see this message on the textbox into user control.
Obviously, doesn't happen :(
Thanks and best regards
I have managed to get the UserControl to work with Binding.
Here is how I have done it:
UserControlWithBinding.xaml:
<UserControl x:Class="SO_app.UserControlWithBinding"
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"
xmlns:local="clr-namespace:SO_app"
mc:Ignorable="d"
d:DesignHeight="20" d:DesignWidth="300">
<Grid Name="IAmGroot"> <!-- Name this grid as you want as this is what we will use for internal Binding -->
<TextBlock Text="{Binding Status}"/><!-- Because this grid is bound to the control it self you will always use this property, unless you rename it :-) -->
</Grid>
Now the code behind of the UserControlWithBinding.xaml.cs:
/// <summary>
/// Interaction logic for UserControlWithBinding.xaml
/// </summary>
public partial class UserControlWithBinding : UserControl
{
public UserControlWithBinding()
{
InitializeComponent();
IAmGroot.DataContext = this;// this is where we set the data context for the grid so it uses the UserControl and not the inherited one. This will allow us to have the DataContext for User Control to be still inherited but the grid will look into a UserControl as an object to assign it to it's data context.
}
public string Status
{
get { return (string)GetValue(StatusProperty); }
set { SetValue(StatusProperty, value); }
}
// Using a DependencyProperty as the backing store for Status. This enables animation, styling, binding, etc...
public static readonly DependencyProperty StatusProperty =
DependencyProperty.Register("Status", typeof(string), typeof(UserControlWithBinding), new PropertyMetadata(null));//note that I am using null and not string.Empty
}
Now let's use our control in xaml:
<local:UserControlWithBinding Status="{Binding PropertyThatYouWantToBindThisControlsText}"/>
This should solve your problem.

expose a field in wpf user control for external use

I am very new to wpf and I would like to create a simple user control that consists of a textblock and a textbox so that I can reuse it. However, I do not really know how to bind the content of the textblock so that it can be set from outside and expose the textbox so that it could be bound to other field from the outside calling xaml.
The following is the code for my user control
<UserControl x:Class="WPFLib.UserControlLibs.TextBoxUsrCtrl"
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"
xmlns:local="clr-namespace:WPFLib.UserControlLibs"
mc:Ignorable="d"
d:DesignHeight="20"
d:DesignWidth="300">
<StackPanel Orientation='Horizontal'
Width='{Binding ActualWidth, ElementName=parentElementName}'
Height='{Binding ActualWidth, ElementName=parentElementName}'>
<Grid HorizontalAlignment='Stretch'>
<Grid.ColumnDefinitions>
<ColumnDefinition Width='1*' />
<ColumnDefinition Width='1*' />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Text='{Binding Text, ElementName=parentElementName}'
Background='Aqua'
Grid.Column='0'
Grid.Row='0' />
<TextBox x:Name='UserTxBox'
Grid.Column='1'
Grid.Row='0'
Background='Red'
HorizontalAlignment='Stretch'
Text='this is a test to see how it works' />
</Grid>
</StackPanel>
</UserControl>
How do I expose the Text from the TextBlock and TextBox so that it could be set and retrieved from the calling xaml?
For example
<Window x:Class="TestWPF.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:local="clr-namespace:TestWPF"
xmlns:controls='clr-namespace:WPFLib.UserControlLibs'
` mc:Ignorable="d"
Title="MainWindow"
Height="350"
Width="525"
WindowState='Maximized'
FontSize='18'>
<StackPanel>
<controls:TextBoxUsrCtrl Width='500' HorizontalAlignment='Left' **Text='NEED TO SET THE TEXT BLOCK HERE'**/>
</StackPanel>
</Window>
You should give it two dependency properties, one for each of the two text properties you want to expose (this is a horrible amount of boilerplate; I use Visual Studio's snippet feature to generate it all). Then in the UserControl XAML, you bind control properties to those.
public partial class TextBoxUsrCtrl : UserControl
{
public TextBoxUsrCtrl()
{
InitializeComponent();
}
#region Text Property
public String Text
{
get { return (String)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register(nameof(Text), typeof(String), typeof(TextBoxUsrCtrl),
new FrameworkPropertyMetadata(null) {
// It's read-write, so make it bind both ways by default
BindsTwoWayByDefault = true
});
#endregion Text Property
#region DisplayText Property
public String DisplayText
{
get { return (String)GetValue(DisplayTextProperty); }
set { SetValue(DisplayTextProperty, value); }
}
public static readonly DependencyProperty DisplayTextProperty =
DependencyProperty.Register(nameof(DisplayText), typeof(String), typeof(TextBoxUsrCtrl),
new PropertyMetadata(null));
#endregion DisplayText Property
}
XAML. I simplified this so the layout works as I think you intended.
Note how the bindings use RelativeSource={RelativeSource AncestorType=UserControl} to bind to the dependency properties we defined above on the UserControl. By default, Binding will bind to properties of UserControl.DataContext, but we're not using that. The reason is that if we set UserControl.DataContext here, that will break the viewmodel property bindings in the final XAML fragment at the end of this answer. Those bindings will look for those properties on our control. There are workarounds but it gets ugly. The way I've done it here is best because it never breaks anybody's assumptions about DataContext inheritance.
<UserControl
x:Class="WPFLib.UserControlLibs.TextBoxUsrCtrl"
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"
xmlns:local="clr-namespace:WPFLib.UserControlLibs"
mc:Ignorable="d"
d:DesignHeight="20"
d:DesignWidth="300"
>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width='*' />
<ColumnDefinition Width='*' />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock
Text='{Binding DisplayText, RelativeSource={RelativeSource AncestorType=UserControl}}'
Background='Aqua'
Grid.Column='0'
Grid.Row='0'
/>
<TextBox
x:Name='UserTxBox'
Grid.Column='1'
Grid.Row='0'
Background='Red'
HorizontalAlignment='Stretch'
Text='{Binding Text, RelativeSource={RelativeSource AncestorType=UserControl}}'
/>
</Grid>
</UserControl>
Usage in window, bound to viewmodel properties:
<local:TextBoxUsrCtrl
Text="{Binding TestText}"
DisplayText="{Binding ShowThisText}"
/>
Lastly, I'm not sure what you were getting at with ElementName=parentElementName. If that's meant to be a reference to a parent control, you can't do that, and it wouldn't be a good idea if you could. You wouldn't want a UserControl constrained by a requirement that a parent control must have a particular name. The answer to that requirement is simply that controls in XAML are only responsible for sizing themselves if they have a fixed size. If they should size to the parent, the parent is always the one responsible for that. So if you want to size two instances of TextBoxUsrCtrl to two different parents, that's fine. Each parent sizes its own children as it pleases.

WPF Binding inner control with parent data context

I made a user control
<UserControl x:Class="MyApp.MyControl"
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" x:Name="uc">
<Grid Width="Auto" Height="Auto">
<TextBlock Text="{Binding Path=DataContext.TextContent, ElementName=uc}"/>
<TextBlock Text="{Binding Path=DataContext.TextContent2, ElementName=uc}"/>
</Grid>
I want the sub-controls in the defined control(uc) will bind to the properties of uc.DataContext. I used the defined control as follows:
<Window x:Class="Tms.TMSClient.Views.MainWindow" Name="window"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:control="clr-namespace:MyApp"
xmlns:ribbon="clr-namespace:Microsoft.Windows.Controls.Ribbon;assembly=RibbonControlsLibrary">
<control:MyControl DataContext="{Binding Path=MyControlVM}"/>
The DataContext which is assigned to the window has this structure: WindowVM.MyControlVM.TextContent.
The given code does not work because the textbox's DataContext is bound to WindowVM instead. I think the problem may be because the inner textbox is bound before the defined control (uc) is, thus the bounded DataContext for uc does not take effect yet.
What I want is: the custom control (MyControl) will be bound to its corresponding viewmodel (MyControlVM), and the inner elements of MyControl will be bound to the properties of MyControlVM.
Do you have any solutions for this problem?
If I understand you correctly, you want to data bind a property from your MyControl view model to a TextBox.Text property inside the MyControl UserControl. If that is correct, then you can use a RelativeSource Binding, or the ElementName syntax that you are already using.
First, make sure that your view model is set as the DataContext for the UserControl:
public MyControl()
{
DataContext = new YourControlViewModel();
}
As child controls automatically inherit their parent's DataContext objects, you can now reference this view model from the TextBox through the MyControl.DataContext property from the UserControl's XAML:
<TextBlock Text="{Binding DataContext.TextContent,
RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />
That's all you need.
<TextBlock Text="{Binding Path=TextContent}"/>
works for me in my test-application.
MainWindow.xaml
<Window x:Class="DataContextTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="clr-namespace:DataContextTest"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<my:MyOuterDataContext />
</Window.DataContext>
<Grid>
<my:MyControl DataContext="{Binding Path=MyInnerDataContext}" />
</Grid>
MyControl.xaml
<UserControl x:Class="DataContextTest.MyControl"
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="300" d:DesignWidth="300">
<Grid>
<TextBlock Text="{Binding Path=TextContent}" />
</Grid>
DataContexts:
public class MyOuterDataContext
{
public MyInnerDataContext MyInnerDataContext { get; set; }
public MyOuterDataContext()
{
MyInnerDataContext = new MyInnerDataContext();
}
}
public class MyInnerDataContext
{
public string TextContent { get { return "foo"; } }
}
By default every control inherits its DataContext from its parent control. Thus there is no need to explicitly bind to it.
Indeed, when you want to bind a control's DataContext to a nested property then you have to specifiy this:
<control:MyControl DataContext="{Binding Path=TextContent}"/>

Dependency Property Binding in UserControl

My solution is implemented in MVVM. The view is a window which hosts a usercontrol. I have created a dependency property for this userControl as below :
public static DependencyProperty ListProperty = DependencyProperty.Register(
"ItemsList", typeof(List<RequiredClass>), typeof(UsercontrolTest));
public List<RequiredClass> ItemsList
{
get { return (List<RequiredClass>)GetValue(ListProperty); }
set
{
SetValue(ListProperty, value);
}
}
This property is bound to my viewmodel property (ListOfItems) in xaml :
<Window x:Class="TestProject.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Test="clr-namespace:TestProject"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Test:UserControlTest Grid.Row="0" ItemsList="{Binding Path=ListOfItems}" />
<Button Grid.Row="1" Content="AddItems" Click="Button_Click" />
</Grid>
</Window>
Also I have initialized the datacontext of the window in codebehind to the viewmodel. Problem is the binding never seems to happen and the set property is never called for the dependency property. Am I missing something here?
Those getters and setters are never called by the binding system (hence you should never place additional code there). The property is probably being set but unless you do something with it in the declaration of the UserControl nothing will be displayed. e.g.
<UserControl Name="control" ...>
<ItemsControl ItemsSource="{Binding ItemsList, ElementName=control}" />
</UserControl>

Categories

Resources