Grid's attached properties always available? - wpf

In the xaml for this window I deleted the Grid container and put a DockPanel.
Yet, I can access a Grid's attached properties from the DockPanel. How is this possible?
Thanks!
<Window x:Class="testWindow"
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"
mc:Ignorable="d"
Title="testWindow" Height="300" Width="300">
<DockPanel Grid.Column="2">
</DockPanel>
</Window>

Because the properties are not on the instance, but are attached - meaning they are defined statically on the Grid class, and that the values are stored in a property container outside of the normal property system.
If you have a DockPanel within a Grid, you use Grid.Column to set which column the DockPanel should be on. Hence, they can be very useful. Attached dependency properties can also be inherited from the parent tree.
For more information, read this link:
http://www.abhisheksur.com/2011/07/internals-of-dependency-property-in-wpf.html
If we take the Grid.Column example, the internals are that somewhere in the Grid class lies a definition like this:
public static readonly DependencyProperty ColumnProperty =
DependencyProperty.RegisterAttached(
"Column",
typeof(int),
typeof(Grid),
new PropertyMetadata(0));
The above code is in fact all that is needed to declare an attached dependency property. Note that there is no getter nor setter here and that the property is static. All it is, is a declaration of behavior - there is no logic to store or retrieve it.
This is because WPF has its own internal store for Dependency Properties (DPs). A normal DP has no backing fields on the classes either. In other words, all DPs are stored internally by WPF. However, WPF still keeps track of which values belong to which instances, so it is still possible to store a Width = 20 for TextBox1. It also means that it is possible to store values that aren't even defined on the classes themselves - as is the case with attached DPs.
Since there are no rules for which controls Grid.Column can be set on, it can be stored even on controls that are not children of a Grid control.

Related

Calburn Micro - IoC is not initialized in WPF designer

I have a WPF application, using Caliburn Micro, and StructureMap for DI.
On my window, I have a ContentControl, the name of which is a property on my view model - at runtime Caliburn successfully locates the correct view based on the type of this property and displays it in that area.
At design-time, though, an exception is thrown: "InvalidOperationException: IoC is not initialized.". Looking at the stack trace, its obvious that Caliburns ViewLocator is attempting to use IoC to create an instance of the view, but the IoC container is not initialized at design time.
So, the question is: How do you initialize Caliburn's IoC at design time?
EDIT:
Here is my UserControl declaration:
<UserControl x:Class="MyNamespace.Views.Checklist.ChecklistQuestionEditView"
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"
xmlns:vm="clr-namespace:MyNamespace.ViewModels.Checklist"
xmlns:cal="clr-namespace:Caliburn.Micro;assembly=Caliburn.Micro.Platform"
d:DataContext="{d:DesignInstance Type=vm:ChecklistQuestionEditDesignerViewModel, IsDesignTimeCreatable=True}"
cal:Bind.AtDesignTime="True"
d:DesignHeight="700" d:DesignWidth="1000">
And here is the ContentControl that causes the issue:
<ContentControl IsTabStop="False" Grid.Row="2" Grid.Column="0" Margin="12" Name="TranslationView"/>
This control is populated by Caliburn's Name conventions via this property in the view model:
private ChecklistQuestionTranslationViewModel _TranslationView;
public ChecklistQuestionTranslationViewModel TranslationView
{
get { return _TranslationView; }
set
{
if (_TranslationView != value)
{
_TranslationView = value;
NotifyOfPropertyChange(() => TranslationView);
}
}
}
If I remove the ContentControl line above from the XAML, all other designer functionality works as expected.
For some reason, you can't copy the exception message from the designer, so I am putting a screen shot here. You can see that Caliburn is attempting to use IoC to create an instance of the View. but I don't have 10 reputation, so I can't post my screenshot.
You might want to have a look at this SO thread I recently asked (and answered): up to now is working great for us.
The main points of that approach are:
Prepare a fake design-time version for each of your view-models, both the container/parent as well as the one mapped to the ContentControl of your view (the child).
Each design-time version has the empty constructor, no external dependencies to be set. It must not rely on DI/IoC container at all.
For every public property data-bound between view and original view-model, the design-time view-model should have a property with the same name ... not necessarily the same type.
This is the case of your child view-model mapped to the ContentControl: the real parent view-model has e.g. a property of type MyCommandBarViewModel, while the fake parent view-model has one of type MyDesignTimeCommandBarViewModel.
This might be applied to a whole visual tree of view-models, the leaves being view-models that just show simple property types (strings, numbers, etc.)
In order to have the Designer and Caliburn.Micro work together to generate those design-time versions, you need to add the following on the root UI element (Window, UserControl, ...):
<Window
d:DataContext="{d:DesignInstance Type=fake:YourDesignTimeViewModel, IsDesignTimeCreatable=True}"
cal:Bind.AtDesignTime="True">

Why is Grid.Row attached property specified without any enclosing Grid?

I am reading code from a WPF project which has the following XAML code (I have omitted the boilerplate parts):
<Window x:Class="AdornedControlSample.Window1"
...
x:Name="window"
...
>
<Canvas
Grid.Row="1"
x:Name="canvas"
>
...
Please note that there is no Grid defined whatsoever anywhere in this XAML file. So, my questions are:
What is the purpose of the Grid.Row="1" within the Canvas definition?
What purpose does x:Name="window" serve? I have not seen anything in the code-behind that references a window. (There are references to Window1, though.)
Question 1
In your example, Grid.Row has no purpose at all. You gave it a value, but that value will not be used because there is no Grid around the Canvas. It also doesn't give an error because it is a valid property/value.
The RowProperty is defined in the Canvas class.
Question 2
It gives a unique name (within the window itself) to the UI-element. For now, it has no purpose. So you can remove it safely. However, if you want to access the window in the code-behind of the view, the x:name serves a purpose. But you can also access the window via the this keyword.

How to disable resizing of user control in WPF

I have Usercontrol.I want to disable its resizing.
The usercontrol is:
<UserControl x:Class="DocumentUpload"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:telerikGrid="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls.GridView"
xmlns:telerikGrid1="clr-namespace:Telerik.Windows.Controls.GridView;assembly=Telerik.Windows.Controls.GridView"
xmlns:telerikInp="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls.Input"
xmlns:telerikNav="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls.Navigation"
xmlns:telerikData="clr-namespace:Telerik.Windows.Data;assembly=Telerik.Windows.Data"
xmlns:telerik="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls" mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Height="auto" Width="auto" MaxWidth="520">
I got to know that there is property called
ResizeMode="NoResize"
.But it is not available in UserControl.Any suugestion?
You have Width and Height set to Auto, so I guess you want to allow the control to take as much space as needed but not more.
Also, UserControl is not resizing by itself, but depends upon the layout that it's part of.
So, the quickest way to fix your issue would be to set HorizontalAlignment="Left" and VerticalAlignment="Top". But you should consider the whole layout of your application and how the UC is affected by-/affects on other components of the UI.
Then the Parent property of your UserControl is holding the Window instance. Most of times, it will be NavigationWindow. Try the below code in loaded event of your UserControl and it will work.
((NavigationWindow)this.Parent).ResizeMode = ResizeMode.NoResize

Change a textbox's text value on a UserControl from a Window in WPF

I have a UserControl (called Invoice) with a textbox (txtReferenceCode) hosted in a TabControl (myTabControl) on MainWindow. From the UserControl I call a window (SearchWindow) which contains a list of stock items. The window needs to return a string value to the textbox contained by the UserControl. I cannot access the textbox on the UserControl from the window and thus cannot pass the string value from the window to the text property.
The UserControl is an instance loaded as a new tabItem (there may be many open as content of tabitems.) I need to only affect the current tabitem instance of the UserControl.
Eg: (Button Click Event in SearchWindow)
Invoice.txtReferenceCode.Text = SearchWindow.txtReferenceCode.Text
I need a simple uncomplicated, solution preferably in VB (but I'll take C# gladly).
I got it! I am posting the solution here for any who struggle with this issue.
XAML
WPF UserControl
<UserControl x:Class="Invoice"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<TextBox x:Name="txtReferenceCode" Width=100 />
</UserControl>
WPF Window
<Window x:Class="SearchWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="300">
<TextBox X:Name="TextToChangeTextBox" Width=100 />
</Window>
Code Behind
Add a Property to your Window
Class SearchWindow
Public ReadOnly Property TextValue
Get
Return TextToChangeTextBox.Text
End Get
End Property
...
End Class
now you can use the property in your window to pass a string to the TextBox on the UserControl.
Public Class Invoice
Private Sub SetValueToTextBox
Dim win As New SearchWindow
win.ShowDialog()
txtReferenceCode.Text = win.TextValue
End Sub
...
End Class
*
And That's it! EASY!
*
There are much better ways to go about doing this (i.e. share a viewmodel between the two windows and let binding update the textbox as needed).
But if you insist on doing it this way, try adding a public modifier to your textbox, that should let you access it like you want to.
<TextBox Name="txtReferenceCode" x:FieldModifier="public"/>

WPF How to expose fields on a UserControl

I have a simple application with just a window and a user control. The user control has a list box. The user control is positioned on the Window and I want to bind the user control's listbox to an element on the window's data context.
The examples I've been able to find have CLR properties on the user control which are accessed in code not via XAML.
<Window x:Class="WpfApplication2b.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:WpfApplication2b="clr-namespace:WpfApplication2b" Title="MainWindow" Height="410" Width="520">
<Grid>
<WpfApplication2b:MyUserControl></WpfApplication2b:MyUserControl>
</Grid>
And here is the user control itself.
<UserControl x:Class="WpfApplication2b.MyUserControl"
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 Background="#FFD8AA13">
<ListBox Height="276" HorizontalAlignment="Left" Margin="12,12,0,0" Name="listBox1" VerticalAlignment="Top" Width="276" />
</Grid>
As you can see it's just a listbox on a different coloured background. I have no idea where to go next :)
I'm guessing that I need to add a code behind property for the list box as a dependency property?
Edit: I've added a dependencyProperty, but I don't think I've quite got the point.
public partial class MyUserControl : UserControl
{
public static readonly DependencyProperty ListBoxProperty;
static MyUserControl()
{
FrameworkPropertyMetadata md = new FrameworkPropertyMetadata();
MyUserControl.ListBoxProperty = DependencyProperty.Register("MyListBox", typeof (ListBox),
typeof (MyUserControl), md);
}
public ListBox MyListBox
{
get
{
return (ListBox) GetValue(ListBoxProperty);
}
set
{
SetValue(ListBoxProperty, value);
}
}
public MyUserControl()
{
InitializeComponent();
}
}
Your UserControl will inherit the DataContext from the Window so you can bind properties on the ListBox as though it were declared in the Window. To make the control more flexible you can declare Dependency Properties for the data items from the DataContext that you want to use (i.e. an ItemsSource collection) and pass them into the control, rather than passing the ListBox out.
I think this question/answer is almost what you're looking for. Essentially you're going to need to make a dependency property (using the AddOwner registration method) and set up the DataBinding on the ListBox's ItemsSource to hook to the Dependency Property. The example in the answer does the same thing for a ComboBox, and should be almost the same for a ListBox.
Exposing inner Control properties for binding in WPF

Resources