wpf mvvm nested user controls datacontext - c#

i have a problem with the datacontext of nested user-controls. The Problem is that the Model in the ViewModel is binded on a DependencyProperty of the first user-control. In the first user-control is a second user-control. The second user-control has also a DependencyProperty. The first user-control binds on that DependencyProperty of the second user-control.
Mainview:
<UserControl x:Class="XXX.XXX.Hmi.Views.L1SetupViewerView"
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:prism="http://prismlibrary.com/"
xmlns:uc="clr-namespace:XXX.XXX.Hmi.UserControls"
d:DesignHeight="450"
d:DesignWidth="800"
prism:ViewModelLocator.AutoWireViewModel="True"
Background="{DynamicResource BaseBrush}"
Foreground="{DynamicResource TextBrush}"
mc:Ignorable="d">
.
.
.
<GroupBox Grid.Row="1" Header="Entry Section">
<uc:L1SetupViewerEntrySectionView Margin="8" Setup="{Binding L1Setup}" />
</GroupBox>
.
.
.
</UserControl>
MainViewModel:
public class L1SetupViewerViewModel : ViewModelBase
{
private L1Setup _l1Setup;
private Pdi _pdi;
public L1SetupViewerViewModel()
{
Title = LanguageProvider.Instance.GetValue("L1SetupViewer_Window_Title");
LanguageProvider.Instance.UiCultureChanged += Instance_UiCultureChanged;
}
#region Properties
public L1Setup L1Setup
{
get { return _l1Setup; }
set { SetProperty(ref _l1Setup, value); }
}
public Pdi Pdi
{
get { return _pdi; }
set { SetProperty(ref _pdi, value); }
}
#endregion
#region Navigation
public override void OnNavigatedTo(NavigationContext navigationContext)
{
if (navigationContext.Parameters.ContainsKey("L1Setup"))
{
L1Setup = navigationContext.Parameters.GetValue<L1Setup>("L1Setup");
}
if (navigationContext.Parameters.ContainsKey("Pdi"))
{
Pdi = navigationContext.Parameters.GetValue<Pdi>("Pdi");
}
}
#endregion
private void Instance_UiCultureChanged(object sender, EventArgs e)
{
Title = LanguageProvider.Instance.GetValue("L1SetupViewer_Window_Title");
}
}
First UserControl:
<UserControl x:Class="XXX.XXX.Hmi.UserControls.L1SetupViewerEntrySectionView"
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:uc="clr-namespace:XXX.XXX.Hmi.UserControls"
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" SharedSizeGroup="c" />
<ColumnDefinition Width="*" SharedSizeGroup="c" />
<ColumnDefinition Width="*" SharedSizeGroup="c" />
<ColumnDefinition Width="*" SharedSizeGroup="c" />
<ColumnDefinition Width="*" SharedSizeGroup="c" />
<ColumnDefinition Width="*" SharedSizeGroup="c" />
<ColumnDefinition Width="*" SharedSizeGroup="c" />
</Grid.ColumnDefinitions>
<uc:L1SetupViewerCellControl Title="Over Speed"
Grid.Row="0"
Grid.Column="0"
Margin="0,0,5,0"
Value="{Binding Setup.EnOveSpd}" />
.
.
.
</Grid>
</UserControl>
First UserControl CodeBehind:
public partial class L1SetupViewerEntrySectionView : UserControl
{
public L1Setup Setup
{
get { return (L1Setup)GetValue(SetupProperty); }
set { SetValue(SetupProperty, value); }
}
public static readonly DependencyProperty SetupProperty =
DependencyProperty.Register("Setup", typeof(L1Setup), typeof(L1SetupViewerEntrySectionView), new PropertyMetadata(null));
public L1SetupViewerEntrySectionView()
{
InitializeComponent();
this.DataContext = this;
}
}
Second UserControl:
<UserControl x:Class="XXX.XXX.Hmi.UserControls.L1SetupViewerCellControl"
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"
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
Margin="0,0,3,0"
Text="{Binding Title}" />
<TextBox Grid.Column="1" Text="{Binding Value}" />
</Grid>
</UserControl>
Second UserControl CodeBehind:
public partial class L1SetupViewerCellControl : UserControl
{
public string Title
{
get { return (string)GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
}
public static readonly DependencyProperty TitleProperty =
DependencyProperty.Register("Title", typeof(string), typeof(L1SetupViewerCellControl), new PropertyMetadata(string.Empty));
public string Value
{
get { return (string)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(string), typeof(L1SetupViewerCellControl), new PropertyMetadata(string.Empty));
public L1SetupViewerCellControl()
{
InitializeComponent();
this.DataContext = this;
}
}
If i run the application i get the following binding error:
System.Windows.Data Error: 40 : BindingExpression path error: 'L1Setup' property not found on 'object' ''L1SetupViewerCellControl' (Name='')'. BindingExpression:Path=L1Setup.EnPor1OutDia; DataItem='L1SetupViewerCellControl' (Name=''); target element is 'L1SetupViewerCellControl' (Name=''); target property is 'Value' (type 'String')
I tried several answers on stackOverflow, nothing worked for me and i don't get it whats wrong.

Setting this.DataContext = this on the L1SetupViewerEntrySectionView breaks the inheritance of the data context from L1SetupViewerView and that's why the binding to L1Setup fails.
Instead of explicitly setting the DataContext in the code-behind, you should either set the DataContext of the root element in UserControl like this:
<Grid DataContext="{Binding RelativeSource={RelativeSource AncestorType=UserControl}}>
...or the source on each binding:
<uc:L1SetupViewerCellControl ...
Value="{Binding Setup.EnOveSpd, RelativeSource={RelativeSource AncestorType=UserControl}}" />
The very same thing applies to the L1SetupViewerCellControl, i.e. remove this.DataContext = this from the constructor and bind to the Value property using a RelativeSource:
<TextBox Grid.Column="1" Text="{Binding Value, RelativeSource={RelativeSource AncestorType=UserControl}}" />

Related

Error in data binding in Xaml

I have tried data binding in WPF.
But it is showing few errors.Please help me.
I am attaching the code.I have create a simple text block and tried to bind the string. Also I want to know how Windows.datacontext works? In my code it is giving an error. please help me out.
Xaml code
<Window x:Class="Shweta.DataBinding"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="DataBinding" Height="300" Width="300">
<Window.DataContext>
<l:DataBinding />
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="54*" />
<ColumnDefinition Width="224*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="59*" />
<RowDefinition Height="202*" />
</Grid.RowDefinitions>
<Grid Grid.Column="1" Grid.Row="1">
<TextBlock Height="23" HorizontalAlignment="Left" Margin="10,10,0,0" Name="textBlock1" Text="{Binding TextString, TargetNullValue=Test}" VerticalAlignment="Top" Width="68" />
</Grid>
</Grid>
</Window>
**Code behind**
namespace Shweta
{
public partial class DataBinding : Window
{
public DataBinding()
{
InitializeComponent();
Setupviewmodel();
}
private void Setupviewmodel
{
TextString="this worked";
}
public string TextString{get;set;}
}
}
Okay so first of all read the error messages ... It clearly says that l is not defined in XAML but still you're trying to use it : <l:DataBinding />...
Fix this by declaring l in your XAML :
<Window x:Class="Shweta.DataBinding"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:l="<your l declaration"/>
Another thing is that you haven't implemented INotifyPropertyChanged so you'r value wont get updated anyway.
Implement this like such :
public partial class DataBinding : Window, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
void NotifyPropertyChanged([CallerMemberName]string propertyName = "")
{
if ( PropertyChanged != null )
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
string text;
public string TextString
{
get { return text; }
set { text = value; NotifyPropertyChanged(); }
}
public DataBinding()
: base()
{
InitializeComponent();
Setupviewmodel();
// as #Nahuel Ianni stated, he has to set DataContext to CodeBehind
// in order to be able to get bindings work
DataContext = this; // <-- only if not binded before
}
public void Setupviewmodel() // forgot to to place ()
// produced error : `A get or set accessor expected`
{
TextString = "this worked";
}
}
Yet another thing is that you have to specify DataContext only when it's not the same as your code behind so you do not need this part :
<Window.DataContext>
<l:DataBinding />
</Window.DataContext>
You are not specifying the DataContext correctly as you are trying to set it up on XAML by using a namespace that has not been declared. For more info on XAML namespaces, check the following link.
In your example it would be on the xaml side:
<Window x:Class="Shweta.DataBinding"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="DataBinding" Height="300" Width="300">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="54*" />
<ColumnDefinition Width="224*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="59*" />
<RowDefinition Height="202*" />
</Grid.RowDefinitions>
<Grid Grid.Column="1" Grid.Row="1">
<TextBlock Height="23" HorizontalAlignment="Left" Margin="10,10,0,0" Name="textBlock1" Text="{Binding TextString, TargetNullValue=Test}" VerticalAlignment="Top" Width="68" />
</Grid>
</Grid>
</Window>
And in your code behind:
namespace Shweta
{
public partial class DataBinding : Window
{
public DataBinding()
{
InitializeComponent();
this.DataContext = this; // Pay attention to this line!
Setupviewmodel();
}
private void Setupviewmodel()
{
TextString="this worked";
}
public string TextString{get;set;}
}
}
The difference with the original version is that I'm not specifying the DataContext on XAML but on the code behind itself.
The DataContext can be considered as the place where the view will retrieve the information from. When in doubt, please refer to this MSDN article or you could learn about the MVVM pattern which is the pillar of working with XAML.
In order to make this work you have to set the DataContext properly. I'd suggest to create a viewmodel class and bind to that. Also I initialized the binding in the codebehind because your namespaces are missing. You can do that in xaml aswell. For now to give you something to work with try this for your codebehind:
public partial class DataBinding : Window
{
public DataBinding()
{
InitializeComponent();
DataContext = new DataBindingViewModel();
}
}
public class DataBindingViewModel
{
public DataBindingViewModel()
{
Setupviewmodel();
}
private void Setupviewmodel()
{
TextString = "this worked";
}
public string TextString { get; set; }
}
And change your view to this:
<Window x:Class="Shweta.DataBinding"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="DataBinding" Height="300" Width="300">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="54*" />
<ColumnDefinition Width="224*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="59*" />
<RowDefinition Height="202*" />
</Grid.RowDefinitions>
<Grid Grid.Column="1" Grid.Row="1">
<TextBlock Height="23" HorizontalAlignment="Left" Margin="10,10,0,0" Name="textBlock1" Text="{Binding TextString, TargetNullValue=Test}" VerticalAlignment="Top" Width="68" />
</Grid>
</Grid>
Note that the Text property will only be set at initialization. If you want DataBinding at runtime your DataBindingViewModel will have to implememnt INPC and throw the PropertyChanged Event after setting the property bound to.

WPF data binding through UserControls

I would like to bind property from the main window's DataContext, above you can see my UserControls and models. So I want to bind the Model.ID.Label1 and Model.ID.Label2 properties to the main_id/card_1/top and main_id/card_1/bottom controls. I hope it's clear. If I enable the
ref_lbl Label it will shows the "lbl1", the card_2 still working with the hardcoded texts but the card_1 will be blank. What should I modify to fix the binding on card_1?
I have an ID UserControl and it contains another UserControl.
XAML:
<UserControl x:Class="stack.ID"
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:Controls="clr-namespace:stack.Controls"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Label Name="ref_lbl" Grid.Row="0" Content="{Binding Label1}" Visibility="Collapsed" />
<Controls:Card x:Name="card_1" Grid.Row="0" TopLabel="{Binding Label1}" BottomLabel="{Binding Label2}" />
<Controls:Card x:Name="card_2" Grid.Row="1" TopLabel="Text 1" BottomLabel="Text 2" />
</Grid>
Code Behind: default, auto generated
Here is the Card UserControl.
XAML:
<UserControl x:Class="stack.Controls.Card"
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" DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Label Grid.Row="0" FontSize="20" Foreground="Black" HorizontalAlignment="Center" VerticalAlignment="Center" Content="{Binding TopLabel}" />
<Label Grid.Row="1" FontSize="20" Foreground="Black" HorizontalAlignment="Center" VerticalAlignment="Center" Content="{Binding BottomLabel}" />
</Grid>
Code Behind:
namespace stack.Controls
{
public partial class Card : UserControl
{
public static readonly DependencyProperty TopLabelProperty = DependencyProperty.Register("TopLabel", typeof(string), typeof(Card), new PropertyMetadata(default(string)));
public static readonly DependencyProperty BottomLabelProperty = DependencyProperty.Register("BottomLabel", typeof(string), typeof(Card), new PropertyMetadata(default(string)));
public Card()
{
InitializeComponent();
}
public string TopLabel
{
get
{
return (string)GetValue(TopLabelProperty);
}
set
{
SetValue(TopLabelProperty, value);
}
}
public string BottomLabel
{
get
{
return (string)GetValue(BottomLabelProperty);
}
set
{
SetValue(BottomLabelProperty, value);
}
}
}
}
And here is my main window.
XAML:
<Window x:Class="stack.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:stack"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:Model />
</Window.DataContext>
<Grid>
<local:ID x:Name="main_id" DataContext="{Binding ID}" />
</Grid>
Code Behind: default, auto generated
And I also have 2 models.
namespace stack
{
public class IDModel
{
private string label1 = "lbl1";
private string label2 = "lbl2";
public string Label1
{
get
{
return label1;
}
set
{
label1 = value;
}
}
public string Label2
{
get
{
return label2;
}
set
{
label2 = value;
}
}
}
public class Model
{
private IDModel id = new IDModel();
public IDModel ID
{
get
{
return id;
}
set
{
id = value;
}
}
}
}
Remove
DataContext="{Binding RelativeSource={RelativeSource Self}}"
from the Card's XAML.
It prevents inheriting the DataContext from its parent ID control, which is necessary when you write
<Controls:Card ... TopLabel="{Binding Label1}" />
Instead write the Content bindings in Card's XAML like this:
<Label ... Content="{Binding TopLabel,
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}" />

Sqlite Data not displaying

Application
x:Class="sqlasynctest.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:sqlasynctest"
xmlns:viewModel="using:sqlasynctest.ViewModel"
RequestedTheme="Light">
<Application.Resources>
<ResourceDictionary>
<viewModel:ViewModelLocator x:Key="Locator" />
</ResourceDictionary>
</Application.Resources>
public class ViewModelLocator
{
public ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
if (!SimpleIoc.Default.IsRegistered<IDal>())
{
SimpleIoc.Default.Register<IDal, Dal>();
}
SimpleIoc.Default.Register<MainViewModel>();
}
public MainViewModel Main
{
get
{
return ServiceLocator.Current.GetInstance<MainViewModel>();
}
}
public static void Cleanup()
{
// TODO Clear the ViewModels
}
}
MainViewModel
public class MainViewModel : ViewModelBase
{
private readonly IDal _iDal;
private IList<User> _user;
public IList<User> Users
{
get { return _user; }
set { Set("Users", ref _user, value); }
}
public MainViewModel(IDal dal)
{
_iDal = dal;
LoadDataCommand = new RelayCommand(async () => await LoadData());
}
public ICommand LoadDataCommand { get; private set; }
public async Task LoadData()
{
Users = await _iDal.LoadAllUser();
}
}
MainPage
<Page
x:Class="sqlasynctest.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:sqlasynctest"
DataContext="{Binding Main, Source={StaticResource Locator}}"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="140"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ListBox Grid.Column="0" Grid.Row="1" SelectionMode="Single"
ItemsSource="{Binding Users}" Margin="120,0,0,40">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding FirstName}"/>
<TextBlock Text="{Binding LastName}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
Table And Methods are fine but i think binding is wrong , help me
LoadData()
Method is not called any where .
I got a solution
protected override void OnNavigatedTo(NavigationEventArgs e)
{
var viewModel = (MainViewModel)DataContext;
if (viewModel != null)
{
viewModel.LoadData();
}
I don't like to touch MainPage.cs
any other way to do this in xaml code
You have LoadDataCommand in your view model, but it is not called from anywhere. There is no magic here – you have to invoke it either from XAML, or from code-behind file. Here's the way this can be done in XAML:
Install Microsoft.Xaml.Behaviors.Uwp.Managed NuGet package.
Modify XAML of your main page:
<Page
...
xmlns:i="using:Microsoft.Xaml.Interactivity"
xmlns:c="using:Microsoft.Xaml.Interactions.Core">
<i:Interaction.Behaviors>
<c:EventTriggerBehavior EventName="Loaded">
<c:InvokeCommandAction Command="{Binding LoadDataCommand}"/>
</c:EventTriggerBehavior>
</i:Interaction.Behaviors>
<Grid ...>
Remove overridden OnNavigatedTo method from the code-behind file.
LoadDataCommand will now be invoked each time MainPage is loaded.
Your problems is that your collection is a List. It does not notify the UI about chnages. User an ObservableCollection instead and it will start to work.

Bind property of childcontrol to parentcontrol

I have a UserControl (Parent) in which is another UserControl (Child). I want to Bind a property in the Child-Control to a property in the Parent-Control. Both UserControls are developed within MVVM. My question now is, how do I access the property of the child-control in the xaml of the parent-control?
Do I have to do something in the code-behind of the child-control or is there another way?
I have an interface called IPerson which looks like:
public interface IPerson
{
string Firstname {get;set;}
string Lastname {get;set;}
}
The parent-control (PersonsView) has a TreeView on the left side and on the right side there's the child-control (PersonView).
The XAML of Persons-View is:
<UserControl x:Class="ScM.Contents.View.PersonsView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:viewModel="clr-namespace:ScM.Contents.ViewModel"
xmlns:view="clr-namespace:ScM.Contents.View"
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">
<UserControl.DataContext>
<viewModel:PersonsViewModel />
</UserControl.DataContext>
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/ScM.Interface;component/GUI/ScMStyles.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<view:PersonsTreeView Grid.Column="0" Margin="2"
OpenPupil="{Binding DataContext.OpenPersonCommand, RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}"
Persons="{Binding DataContext.Persons, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged,
RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}" />
<GridSplitter Grid.Column="1" Width="2" ShowsPreview="True" VerticalAlignment="Stretch"
HorizontalAlignment="Center" Margin="0,2" />
<view:PersonView Grid.Column="2" Margin="2"></view:PersonView>
</Grid>
</UserControl>
The Person-View consist only of labels and textboxes. The PersonViewModel looks like:
internal class PersonViewModel : ViewModelBase
{
private readonly PersonModel _personModel;
private IPerson _person;
public PersonViewModel()
{
_personModel = new PersonModel();
}
public IPerson Person
{
get { return _person; }
set
{
_person = value;
OnPropertyChanged();
}
}
}
You can either name your parent control to point to it using ElementName
<ParentControl x:Name=ParentControl>
<ChildControl SomeChildControlProperty="{Binding SomeParentControlProperty,
ElementName=ParentControl}"/>
</ParentControl>
or you can use RelativeSource with FindAncestor :
<ParentControl>
<ChildControl SomeChildControlProperty="{Binding SomeParentControlProperty,
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type ParentControl}}}"/>
</ParentControl>
I didn't test this code though so the syntax might not be exactly right

Create box with title and text in silverlight

can I create something like this in silverlight? A box with editable title and the rest of the text
http://docs.jboss.org/seam/3/latest/reference/en-US/html/images/remoting-model-customer-address-uml.png
You could create a custom user control:
XAML:
<UserControl x:Class="WpfApplication1.MyBox"
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>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBox Text="{Binding Header,UpdateSourceTrigger=PropertyChanged}"
BorderBrush="Black" BorderThickness="1" Margin="2" />
<TextBox Text="{Binding Text,UpdateSourceTrigger=PropertyChanged}"
TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto"
AcceptsReturn="True"
BorderBrush="Black" BorderThickness="1" Margin="2" Grid.Row="1" />
</Grid>
</UserControl>
Code behind:
using System.Windows;
using System.Windows.Controls;
namespace WpfApplication1
{
public partial class MyBox : UserControl
{
public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register("Header", typeof(string), typeof(MyBox));
public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Content", typeof(string), typeof(MyBox));
public string Header
{
get { return GetValue(HeaderProperty) as string; }
set { SetValue(HeaderProperty, value); }
}
public string Text
{
get { return GetValue(TextProperty) as string; }
set { SetValue(TextProperty, value); }
}
public MyBox()
{
InitializeComponent();
this.DataContext = this;
}
}
}
A sample:
XAML:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
xmlns:local="clr-namespace:WpfApplication1">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<local:MyBox x:Name="box1" Header="Type a header..." Text="Type a content..." Grid.Row="0" Grid.Column="0" BorderBrush="Black" BorderThickness="1" Margin="10" />
<local:MyBox x:Name="box2" Header="Type a header..." Text="Type a content..." Grid.Row="0" Grid.Column="1" BorderBrush="Black" BorderThickness="1" Margin="10" />
<Button Content="Show" Grid.Row="1" Grid.Column="0" Click="Button_Click" />
</Grid>
</Window>
Code behind:
using System.Windows;
namespace WpfApplication1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show(string.Format("{0}\n{1}\n\n{2}\n{3}", box1.Header, box1.Text, box2.Header, box2.Text));
}
}
}
This is WPF but should be fine in Silverlight too, except the MessageBox stuff but it's only for debugging purposes...
EDIT:
Here is a sample for dynamic generation:
XAML:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
xmlns:local="clr-namespace:WpfApplication1">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel x:Name="panel" Orientation="Horizontal">
<local:MyBox x:Name="box1" Header="Type a header..." Text="Type a content..." Grid.Row="0" Grid.Column="0" BorderBrush="Black" BorderThickness="1" Margin="10" />
</StackPanel>
<Button Content="Add" Grid.Row="1" Grid.Column="0" Click="Button_Click" />
</Grid>
</Window>
CodeBehind:
using System.Windows;
using System.Windows.Media;
namespace WpfApplication1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
panel.Children.Add(new MyBox
{
Header = "Another box",
Text = "...",
BorderBrush = Brushes.Black,
BorderThickness = new Thickness(1),
Margin = new Thickness(10)
});
}
}
}

Categories