WPF Closing a Window from the a UserControl MVVM - wpf

I currently have a problem with my Binding because upon pressing a Button, it should close a certain Window but it doesn't. This is a more detailed description of the situation:
In my Application, I have the following button:
Upon pressing it, a new Window is launched. It contains a UserControl and is used as a DialogBox to confirm that the user wants to save all changes. This is the code that launches the DialogBox (Window). Note that the window is passed by reference:
private void OpenRegisterDialog(string changes)
{
window = new Window
{
Title = "Confirmation",
ResizeMode = ResizeMode.NoResize,
WindowStartupLocation = WindowStartupLocation.CenterScreen
};
SaveConfirmationDg = new SaveConfirmationDialog(ref window);
window.ShowDialog();
}
Note that the Content of the Window has not been set yet, I will document this after.
This is how the DialogBox looks like (upon pressing OUI or NON, the window should be closing but it isn't):
This is the xaml used to generate the DialogBox which is a UserControl nested into our DialogBox Window.
SaveConfirmation.xaml
<Grid HorizontalAlignment="Center" VerticalAlignment="Center" Height="200" Width="350" Background="Black">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White" Text="Voulez-vous enregistrer les modifications?" />
</Grid>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid Grid.Column="0">
<Button Foreground="White" Content="OUI" Command="{Binding Close}" CommandParameter="close" Margin="10,0" />
</Grid>
<Grid Grid.Column="1">
<Button Foreground="White" Content="NON" Command="{Binding Close}" CommandParameter="close" Margin="10,0" />
</Grid>
</Grid>
As I am using the MVVM pattern, I am setting the DataContext to SaveConfirmationDialogViewModel.cs in the Code-Behind (Note that the window created is passed as a reference).
public SaveConfirmationDialog(ref Window window)
{
InitializeComponent();
DataContext = new SaveConfirmationDialogViewModel(ref window);
}
Finally, here is how I create and assign the Content of the DialogBox:
SaveConfirmationDialogViewModel.Cs
class SaveConfirmationDialogViewModel : ViewModelBase
{
public Window CurrentWindow;
public MyICommand<string> Close { get; private set; }
SaveConfirmationDialog SaveConfDg;
public SaveConfirmationDialogViewModel(ref Window window)
{
SaveConfDg = new SaveConfirmationDialog();
window.Content = SaveConfDg;
window.SizeToContent = SizeToContent.WidthAndHeight;
CurrentWindow = window;
Close = new MyICommand<string>(ExitDialog);
}
private void ExitDialog(string exit)
{
CurrentWindow.Close();
}
}
Note that CurrentWindow is assigned a reference of window to be able to use it outside of the Constructor. After pressing the OUI and NON buttons the ExitDialog method of the Close command should be used to close the Window but I see it's not even called because I have checked by placing a breakpoint.
I am thinking the problem might be with the DataContext. Does anyone have a clue what the problem might
be?
Thanks in advance!

Finally, the problem was really simple, I just needed to comment out the first line of my Constructor and pass the SaveConfirmationDialog object from the Code-Behind
SaveConfirmationDialogViewModel.cs
public SaveConfirmationDialogViewModel(ref Window window, SaveConfirmationDialog SaveConfDg)
{
//SaveConfDg = new SaveConfirmationDialog();
window.Content = SaveConfDg;
window.SizeToContent = SizeToContent.WidthAndHeight;
CurrentWindow = window;
Close = new MyICommand<string>(ExitDialog);
}
SaveConfirmationDialog.xaml.cs
public SaveConfirmationDialog(ref Window window)
{
InitializeComponent();
//Added this as second parameter
DataContext = new SaveConfirmationDialogViewModel(ref window, this);
}

Related

WPF custom control not working as expected in Listview

I want to put an editabletextblock cutom control in a Listview datatemplate. I'm following this article and it works well.
But when i'm put this control in a Listview datatemplate, on double click on the Textblock, the event OnMouseDoubleClick of the custom control is fired but the Textbox is never display.
My Datatemplate :
<DataTemplate x:Key="ItemTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal"
Grid.Column="0">
<Image Source="{Binding Icon}"
Margin="0 0 4 0" />
<localp:EditableTextBlock Text="{Binding Tag, Mode=TwoWay}"
VerticalAlignment="Center" />
</StackPanel>
</Grid>
<ListView
ItemTemplate={StaticResource ItemTemplate}
.... />
And i don't know why the OnMouseDoubleClick EditableTextBlock is fired but the inner Textbox is never displayed as expected.
Thanks is advance for your help,
Regards
Change the default values of TextBlockForegroundColorProperty and TextBoxForegroundColorProperty from null to something else:
public static readonly DependencyProperty TextBlockForegroundColorProperty =
DependencyProperty.Register("TextBlockForegroundColor",
typeof(Brush), typeof(EditableTextBlock), new UIPropertyMetadata(Brushes.Black));
public static readonly DependencyProperty TextBoxForegroundColorProperty =
DependencyProperty.Register("TextBoxForegroundColor",
typeof(Brush), typeof(EditableTextBlock), new UIPropertyMetadata(Brushes.Black));
Or set them in you Xaml:
<local:EditableTextBlock TextBlockForegroundColor="Black" TextBoxForegroundColor="Black" ... />
Edit
you can set keyboard focus to the TextBox, however, you should set e.Handled to true, or the OnTextBoxLostFocus will execute and hides your TextBox.
protected override void OnMouseDoubleClick(MouseButtonEventArgs e)
{
base.OnMouseDoubleClick(e);
this.m_TextBlockDisplayText.Visibility = Visibility.Hidden;
this.m_TextBoxEditText.Visibility = Visibility.Visible;
if (m_TextBoxEditText.IsKeyboardFocusWithin ==false)
{
Keyboard.Focus(m_TextBoxEditText);
e.Handled = true;
m_TextBoxEditText.CaretIndex = m_TextBoxEditText.Text.Length;
}
}

WPF MVVM pattern

i am doing a simple project with mvvm pattern. its about one list that every row has one textbox and delete button and at
buttom we have one text box and add button like this:
name1 buttondelete
name2 buttondelete
name3 buttondelete
.
.
textbox buttonadd
with click the buttondelete the row should delete and with click bottonadd the text of textbox should insert in list as new
row.
i have three layer Sepand.WPFProject.Model , Sepand.WPFProject.ViewModel , Sepand.WPFProject.View;
in model i have context and repository and model (here my model is Category that have Name & ID property) class. repository is like this:
public class ModelRepository<T>
where T : class
{
ModelDbContext ctx = new ModelDbContext();
public IQueryable<T> GetAll()
{
IQueryable<T> query = ctx.Set<T>();
return query;
}
public void Add(T entity)
{
ctx.Set<T>().Add(entity);
ctx.SaveChanges();
}
public void Delete(T entity)
{
ctx.Set<T>().Remove(entity);
ctx.SaveChanges();
}
in viewModel i have categoryViewModel class like this:
public class CategoryViewModel
{
ModelRepository<Category> repository = new ModelRepository<Category>();
ObservableCollection<Category> categories = new ObservableCollection<Category>();
Category category = new Category();
public ObservableCollection<Category> GetAll()
{
IQueryable<Category> categoryRepository = repository.GetAll();
foreach (Category Category in categoryRepository)
categories.Add(Category);
return categories;
}
public ObservableCollection<Category> GetAllCategories
{
get { return GetAll(); }
}
public string TxtName
{
get { return category.Name; }
set { category.Name = value; }
}
in View in code behind i have
this.DataContext = new CategoryViewModel();
and in XAML i have
<Window.Resources>
<DataTemplate x:Key="CategoryTemplate">
<Border Width="400" Margin="5" BorderThickness="1" BorderBrush="SteelBlue" CornerRadius="4">
<StackPanel Grid.Row="0" Orientation="Horizontal">
<TextBlock Width="300" Margin="5" Text="{Binding Path=Name}"></TextBlock>
<Button Name="btnDeleteCategory" Width="50" Margin="5" Click="btnDeleteCategory_Click" >-</Button>
</StackPanel>
</Border>
</DataTemplate>
</Window.Resources>
.
.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ListBox Grid.Column="0" Grid.Row="0" Name="lstCategory" ItemTemplate="{StaticResource CategoryTemplate}" ItemsSource="{Binding Path=GetAllCategories}"/>
<StackPanel Margin="5" Grid.Column="0" Grid.Row="1" Orientation="Horizontal">
<Label Content="Name : "/>
<TextBox Name="TxtName" Text="{Binding Path=TxtName ,Mode=TwoWay}" Width="260"/>
<Label Width="50"/>
<Button Width="50" Content="+" Name="btnAddCategory" Click="AddCategory_Click" />
</StackPanel>
</Grid>
</Grid>
and now when i run app the listbox populated with data from database; but i could not write code for addbutton and
delete button;
could anyone tell me what should i do?
and why i could not bind the text of textbox in list to TxtName Property of CategoryViewModel class ?
i mean here
<TextBlock Width="300" Margin="5" Text="{Binding Path=Name}"></TextBlock>
when i write Binding Path=TxtName the list box would not show data but with Binding Path=Name
it shows data from database
Your question is a bit scattered. But I'll try address what I think are your issues.
You say in the code behind you have:
this.DataContext = new CategoryViewModel();
But nothing else.
First thing to do with checking why your button isn't working would be to see what action it is performing. Your XAML states it's using a click event:
btnDeleteCategory_Click
Where's that? Is it not in your code-behind too? It might be that you've not got anything and that's why your button isn't doing anything - you've not instructed it to do anything!
In MVVM you should be binding your button using Commands in your ViewModel, similarly to how you bind data to Properties in your ViewModel.
You need something like:
Command="{Binding Path=DeleteCommand}"
in your view, and:
public ICommand DeleteCommand
{
get { return new DelegateCommand<object>(FuncToCall, FuncToEvaluate); }
}
private void FuncToCall(object context)
{
//this is called when the button is clicked - Delete something
}
private bool FuncToEvaluate(object context)
{
//this is called to evaluate whether FuncToCall can be called
//for example you can return true or false based on some validation logic
return true;
}
Binding to TxtName might not be working because it does not implement/call PropertyChanged.

Use a UserControl inside a Ribbon

I want to use a UserControl inside a RibbonControl.
For example:
<RibbonWindow
xmlns:uc="clr-namespace:UserControl1;assembly=UserControl1">
<Grid ShowGridLines="False" Margin="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="100*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100*"/>
</Grid.ColumnDefinitions>
<Ribbon Grid.Row="0">
<RibbonApplicationMenu >
<RibbonApplicationMenuItem x:Name="miExit" ImageSource="Images/large_exit.png" Header="Exit" />
</RibbonApplicationMenu>
<RibbonTab Header="Test">
<uc:RibbonGroups/>
</RibbonTab>
</Ribbon>
<uc:Content Grid.Row="1" />
</Grid>
</RibbonWindow>
You see two UserControls, uc:RibbonGroups and uc:Content. While the second one (uc:Content) works fine, the UserControl inside the RibbonControl won't work.
What i missed?
I also try this approach:
How to set the usercontrol for ribbon window in WPF?
an set a grid inside the RibbonTab and then the UserControl;
<Ribbon Grid.Row="0">
...
<Grid>
<RibbonTab Header="Test">
<uc:RibbonGroups/>
</RibbonTab>
</Grid>
</Ribbon>
instead of
<Ribbon Grid.Row="0">
...
<RibbonTab Header="Test">
<uc:RibbonGroups/>
</RibbonTab>
</Ribbon>
Edit:
UserControl now only holds the content of RibbonTab, RibbonTab itself moved to the main window
<UserControl ...>
<StackPanel Orientation="Horizontal">
<RibbonGroup Header="Test" >
<RibbonButton SmallImageSource="Images/small_save.png"
LargeImageSource="Images/large_save.png" />
<Image Source="Images/large_expert_enabled.png"></Image>
</Stackpanel>
</UserControl>
RibbonGroup are shown with the Header but without the images, and the separate Image are shown itself. So maybe there are now any suggestions what goes wrong?
EDIT2:
If i step into with Snoop, the RibbonButtons and their corresponding images are present.
EDIT3:
I tried another way with resources, but same problem as above..
How it looks, when i have the RibbonTab in the resource/UserControl:
http://s12.postimg.org/lpposl48t/DLL_Ribbon_Tab_fail_part.png
How it looks, when i have the RibbonGroup in the resource/UserControl:
http://s12.postimg.org/oiiwcm4l9/DLL_Ribbon_Group_fail_part.png
After a lot of research i found this from Ben Barefield:
http://www.benbarefield.com/blog/2011/03/04/ribbon-tab-definition-on-usercontrol/
He use a trick and move the ribbontab into a resourcedictionary.
Works well, but i also wanted to add some click events to this ribbontab (with view specific actions....) so i decided to fall back to the usercontrol.
The trick is, to detach the ribbontab from the usercontrol before adding it to the other control.
In detail:
add this methods to the usercontrol codebehind:
private void AttachTabToRibbon(RibbonTab tab)
{
Ribbon Ribbon = null;
Ribbon = getRibbon();
if (Ribbon == null)
return;
Ribbon.Items.Add(tab);
}
private Ribbon getRibbon()
{
var control = VisualTreeHelper.GetParent(this);
Ribbon Ribbon = null;
while (control != null && Ribbon == null)
{
var numberOfChildren = VisualTreeHelper.GetChildrenCount(control);
for (int i = 0; i < numberOfChildren; ++i)
{
var child = VisualTreeHelper.GetChild(control, i);
if (child is Ribbon)
{
Ribbon = child as Ribbon;
return Ribbon;
}
}
control = VisualTreeHelper.GetParent(control);
}
return null;
}
private void userControl_Loaded(object sender, RoutedEventArgs e)
{
Ribbon ribbonMenu = (Ribbon)this.FindName("ribbon");
RibbonTab ribbonTabAdminInterface = (RibbonTab)this.FindName("ribbonTab");
ribbonMenu.Items.Remove(ribbonTab);
ucStackPanel.Children.Remove(ribbonMenu);
AttachTabToRibbon(ribbonTab);
}
furthermore call the userControl_Loaded:
<UserControl ...
Loaded="userControl_Loaded"
>
<StackPanel x:Name="ucStackPanel">
<Ribbon x:Name="ribbon" >
<Ribbon.ApplicationMenu>
<RibbonApplicationMenu
</RibbonApplicationMenu>
</Ribbon.ApplicationMenu>
<RibbonTab x:Name="ribbonTab"/>
...
</Ribbon>
...
</StackPanel>

How does WPF DataGrid get frozen rows/columns working?

I created a user control based on Grid (not DataGrid), which is wrapped in a ScrollViewer. Now I would like to have frozen rows/columns capability just like in DataGrid, but couldn't figure out how.
Can somebody give me some insight how it is done in WPF DataGrid?
After having this problem by myself I want to share what I've found out so far.
DataGrid uses two different methods for that.
First: The RowHeader
This is the simplified Template for DataGridRow:
<Border x:Name="DGR_Border" ... >
<SelectiveScrollingGrid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<DataGridRowHeader Grid.RowSpan="2"
SelectiveScrollingGrid.SelectiveScrollingOrientation="Vertical" ... />
<DataGridCellsPresenter Grid.Column="1" ... />
<DataGridDetailsPresenter Grid.Column="1" Grid.Row="1"
SelectiveScrollingGrid.SelectiveScrollingOrientation="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}},
Path=AreRowDetailsFrozen, Converter={x:Static DataGrid.RowDetailsScrollingConverter},
ConverterParameter={x:Static SelectiveScrollingOrientation.Vertical}}" ... />
</SelectiveScrollingGrid>
</Border>
As you can see DataGrid uses the SelectiveScrollingOrientation attached property to hold the RowHeader in position. If this property is set (or changing) it creates an adapted TranslateTransform bound to the parental ScrollViewer Offset for the element. See the details in source code.
Second: The FrozenColumns
This stuff takes place in DataGridCellsPanel ArrangeOverride(). It uses a private ArrangeState class "to maintain state between arrange of multiple children".
private class ArrangeState
{
public ArrangeState()
{
FrozenColumnCount = 0;
ChildHeight = 0.0;
NextFrozenCellStart = 0.0;
NextNonFrozenCellStart = 0.0;
ViewportStartX = 0.0;
DataGridHorizontalScrollStartX = 0.0;
OldClippedChild = null;
NewClippedChild = null;
}
public int FrozenColumnCount { get; set; }
public double ChildHeight { get; set; }
public double NextFrozenCellStart { get; set; }
public double NextNonFrozenCellStart { get; set; }
public double ViewportStartX { get; set; }
public double DataGridHorizontalScrollStartX { get; set; }
public UIElement OldClippedChild { get; set; }
public UIElement NewClippedChild { get; set; }
}
After initializing the state with
private void InitializeArrangeState(ArrangeState arrangeState)
{
DataGrid parentDataGrid = ParentDataGrid;
double horizontalOffset = parentDataGrid.HorizontalScrollOffset;
double cellsPanelOffset = parentDataGrid.CellsPanelHorizontalOffset;
arrangeState.NextFrozenCellStart = horizontalOffset;
arrangeState.NextNonFrozenCellStart -= cellsPanelOffset;
arrangeState.ViewportStartX = horizontalOffset - cellsPanelOffset;
arrangeState.FrozenColumnCount = parentDataGrid.FrozenColumnCount;
}
it calls
ArrangeChild(children[childIndex] as UIElement, i, arrangeState);
for all realized childs and calculates the estimated width for non realized childs/columns.
double childSize = GetColumnEstimatedMeasureWidth(column, averageColumnWidth);
arrangeState.NextNonFrozenCellStart += childSize;
At the end the values will be set in the appropriate fields in DataGrid.
private void FinishArrange(ArrangeState arrangeState)
{
DataGrid parentDataGrid = ParentDataGrid;
// Update the NonFrozenColumnsViewportHorizontalOffset property of datagrid
if (parentDataGrid != null)
{
parentDataGrid.NonFrozenColumnsViewportHorizontalOffset = arrangeState.DataGridHorizontalScrollStartX;
}
// Remove the clip on previous clipped child
if (arrangeState.OldClippedChild != null)
{
arrangeState.OldClippedChild.CoerceValue(ClipProperty);
}
// Add the clip on new child to be clipped for the sake of frozen columns.
_clippedChildForFrozenBehaviour = arrangeState.NewClippedChild;
if (_clippedChildForFrozenBehaviour != null)
{
_clippedChildForFrozenBehaviour.CoerceValue(ClipProperty);
}
}
The details for ArrangeChild(UIElement child, int displayIndex, ArrangeState arrangeState) you can find from line 1470 in source code.
Conclusion
It's not as simple making columns are frozen. Even though this will work (apart from clipping and scrollbar over whole width)
<ListView ItemsSource="some rows">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="Fixed"
Background="LightBlue" Width="300"
SelectiveScrollingGrid.SelectiveScrollingOrientation="Vertical" />
<TextBlock Grid.Column="1" Text="Scrolled"
Background="LightGreen" Width="300" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
this will not:
<ScrollViewer HorizontalScrollBarVisibility="Auto">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="Fixed"
Background="LightBlue" Width="300"
SelectiveScrollingGrid.SelectiveScrollingOrientation="Vertical" />
<TextBlock Grid.Column="1" Text="Scrolled"
Background="LightGreen" Width="300" />
</Grid>
</ScrollViewer>
The reason is that DataGridHelper.FindVisualParent<ScrollViewer>(element) (see from line 149 in souce code) in SelectiveScrollingOrientation attached property fails. Maybe you find workarounds e.g. create your own attached property with a copy of the original code but get the ScrollViewer by name. Otherwise I think you have to do many things from scratch.
Datagrid Column and Row has a property called "Frozen"
if you want to freeze a column i recommend you do the following
either you want it on selected Row or Column Event and then on the Event Get the Column/Row and mark it as Frozen = true
or create another button or a context menu on mouse right click on which you Freeze/Unfreeze the currently marked
column/row
hope this helps

Binding Silverlight UserControl custom properties to its' elements

I'm trying to make a simple crossword puzzle game in Silverlight 2.0. I'm working on a UserControl-ish component that represents a square in the puzzle. I'm having trouble with binding up my UserControl's properties with its' elements. I've finally (sort of) got it working (may be helpful to some - it took me a few long hours), but wanted to make it more 'elegant'.
I've imagined it should have a compartment for the content and a label (in the upper right corner) that optionally contains its' number. The content control probably be a TextBox, while label control could be a TextBlock. So I created a UserControl with this basic structure (the values are hardcoded at this stage):
<UserControl x:Class="XWord.Square"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
FontSize="30"
Width="100" Height="100">
<Grid x:Name="LayoutRoot" Background="White">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock x:Name="Label" Grid.Row="0" Grid.Column="1"
Text="7"/>
<TextBox x:Name="Content" Grid.Row="1" Grid.Column="0"
Text="A"
BorderThickness="0" />
</Grid>
</UserControl>
I've also created DependencyProperties in the Square class like this:
public static readonly DependencyProperty LabelTextProperty;
public static readonly DependencyProperty ContentCharacterProperty;
// ...(static constructor with property registration, .NET properties
// omitted for brevity)...
Now I'd like to figure out how to bind the Label and Content element to the two properties. I do it like this (in the code-behind file):
Label.SetBinding( TextBlock.TextProperty, new Binding { Source = this, Path = new PropertyPath( "LabelText" ), Mode = BindingMode.OneWay } );
Content.SetBinding( TextBox.TextProperty, new Binding { Source = this, Path = new PropertyPath( "ContentCharacter" ), Mode = BindingMode.TwoWay } );
That would be more elegant done in XAML. Does anyone know how that's done?
First, set the DataContext on the UserControl using {RelativeSource Self}:
<UserControl x:Class="XWord.Square"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
FontSize="30"
Width="100" Height="100"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
Now you can bind the individual elements to the properties of the usercontrol:
<TextBlock x:Name="Label" Grid.Row="0" Grid.Column="1"
Text="{Binding LabelText}"/>
<TextBox x:Name="Content" Grid.Row="1" Grid.Column="0"
Text="{Binding ContentCharacter}" BorderThickness="0" />
For SL 2.0, you'll need to set the DataContext on the UserControl's Loaded event handler.
private void UserControl_Loaded( object sender, RoutedEventArgs e ) {
LayoutRoot.DataContext = this;
}
As Silverlight cannot use FindAncestor technique you can use a trick similar to the one that sets the UserControl's name, but without breaking its functionality by using the name of the LayoutRoot...
<UserControl x:Class="XWord.Square"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
FontSize="30"
Width="100" Height="100">
<Grid x:Name="LayoutRoot" Background="White">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock x:Name="{Binding Path=Parent.LabelText, ElementName=LayoutRoot}" Grid.Row="0" Grid.Column="1"
Text="7"/>
<TextBox x:Name="{Binding Path=Parent.ContentCharacter, ElementName=LayoutRoot}" Grid.Row="1" Grid.Column="0"
Text="A"
BorderThickness="0" />
</Grid>
</UserControl>
It worked in SL3 without having to add any additional code (I'm using it in a WP7 app), but don't know if you can use it in SL2. Well, I realize now how this question is old, hope it's still helpful, I've arrived here because the answers I got for the same problem in WP7 didn't convince me.
I think you are looking for UI Element to Element Binding which is a feature of Silverlight 3.
I may not be understanding your issue exactly. In Silverlight, you are able to bind to almost any data object. So, if you have a PuzzleSquare class that contains properties Content and Label, you may bind to these properties directly from the object.
Let's say you created a simple object PuzzleSquare:
public class PuzzleSquare
{
public string Content{ get; set; }
public string Label{ get; set; }
public void PuzzleSquare(){};
public void PuzzleSquare(string label, string content):this()
{
Content = content;
Label = label;
}
}
So, if you are building the app with the classic view/code behind model, your code behind would add this object to the DataContext property of the grid on page load:
LayoutRoot.DataContext = new PuzzleSquare("1", "A");
Your Xaml would bind to the Square property:
<TextBlock x:Name="Label" Grid.Row="0" Grid.Column="1"
Text="{Binding Label}"/>
<TextBox x:Name="Content" Grid.Row="1" Grid.Column="0"
Text="{Binding Content}" BorderThickness="0" />
Does that make sense?
ib.
This worked in Silverlight 4.0
Put a name on the UserControl, and then refer to it in the TextBlock
<UserControl x:Class="XWord.Square"
...omitted for brevity ...
x:Name="Square">
<TextBlock x:Name="Label" ...
Text="{Binding Path=LabelText,ElementName=Square}"/>
Try this:
Public ReadOnly TextProperty As DependencyProperty = DependencyProperty.Register("Text", GetType(String), GetType(ButtonEdit), New System.Windows.PropertyMetadata("", AddressOf TextPropertyChanged))
Public Property Text As String
Get
Return GetValue(TextProperty)
End Get
Set(ByVal value As String)
SetValue(TextProperty, value)
End Set
End Property
Private Sub TextPropertyChanged()
If String.IsNullOrEmpty(Text) Then
TextBox1.Text = ""
Else
TextBox1.Text = Text
End If
End Sub
Private Sub TextBox1_LostFocus(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles TextBox1.LostFocus
Text = TextBox1.Text
End Sub
I can bind in both XAML and code behind.

Resources