What simple thing am I missing here? Why doesn't my copy display on the screen?
<Window x:Class="DeleteThis.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" >
<Grid>
<StackPanel>
<TextBlock Text="{Binding Path=SomeCopy}" Height="35" Width="100" Margin="10"/>
</StackPanel>
</Grid>
and my code-behind.
public partial class MainWindow : Window
{
private string _someCopy;
public string SomeCopy
{
get
{
return _someCopy;
}
set
{
_someCopy = value;
}
}
public MainWindow()
{
InitializeComponent();
SomeCopy = "why doesn't this display";
}
}
You never set the DataContext of the Window. Change your XAML to this...
<TextBlock Text="{Binding}" Height="35" Width="100" Margin="10"/>
...and change your code behind to add the DataContext line...
public MainWindow()
{
InitializeComponent();
SomeCopy = "why doesn't this display";
this.DataContext = SomeCopy;
}
Your current issue has nothing to do with needing a DependencyProperty as mentioned in the other answers.
WPF never finds out that the property changed.
To fix it, you can turn the property into a dependency property.
EDIT: You also need to bind to the property on the Window itself, like this
<TextBlock Text="{Binding Path=SomeCopy, RelativeSource={RelativeSource Self}}" ... />
SLaks's answer is the correct one. But making dependency properties manually is annoying, so I link you to my favorite solution: A custom PostSharp NotifyPropertyChangedAttribute that, when used in conjunction with PostSharp, makes all the properties of any given class into dependency properties.
Related
I have a Silverlight XAML usercontrol that I want to use to show that elements are grouped together in the layout. The xaml is:
<UserControl x:Class="StylingLibrary.FieldSet"
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:System="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d"
d:DesignWidth="200" d:DesignHeight="200">
<Grid x:Name="FieldsetLayoutRoot" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Border HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Style="{StaticResource FieldsetBorder}">
<ContentPresenter x:Name="TheFieldsetContentPresenter" Content="{Binding Content}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0"/>
</Border>
<Border HorizontalAlignment="Left" VerticalAlignment="Top" Style="{StaticResource FieldsetTitleBackground}">
<TextBlock x:Name="FieldsetTitleTextBlock" HorizontalAlignment="Left" VerticalAlignment="Top" Text="{Binding Title}" Style="{StaticResource FieldsetTitle}"/>
</Border>
</Grid>
</UserControl>
And its backing code contains mainly dependency properties:
public partial class FieldSet : UserControl
{
public FieldSet()
{
TheFieldsetContentPresenter.DataContext = this;
FieldsetTitleTextBlock.DataContext = this;
// Required to initialize variables
InitializeComponent();
}
public String Title
{
get { return (String)GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
}
public static readonly DependencyProperty TitleProperty =
DependencyProperty.Register("TitleProperty", typeof(String), typeof(FieldSet), null);
public new FrameworkElement Content
{
get { return (FrameworkElement)GetValue(MyContentProperty); }
set { SetValue(MyContentProperty, value); }
}
public static readonly DependencyProperty MyContentProperty =
DependencyProperty.Register("ContentProperty", typeof(FrameworkElement), typeof(FieldSet), null);
}
Now whenever I try to use it like so:
<Styling:FieldSet Title="Projects">
<TextBlock Text="test" />
</Styling:FieldSet>
Visual studio (2010) tells me that a NullReferenceException was thrown and it cannot create an instance of FieldSet. When trying to build and run the project, this is the error:
{System.Windows.Markup.XamlParseException: The invocation of the constructor on type 'StylingLibrary.FieldSet' that matches the specified binding constraints threw an exception. [Line: 81 Position: 44] ---> System.NullReferenceException: Object reference not set to an instance of an object.
at StylingLibrary.FieldSet..ctor()
--- End of inner exception stack trace ---
at System.Windows.Application.LoadComponent(Object component, Uri resourceLocator)
at ProjectsOverview.Views.ProjectsList.InitializeComponent()
at ProjectsOverview.Views.ProjectsList..ctor(ProjectsListViewModel m)}
What have I done wrong here?
Change the constructor to
public FieldSet()
{
InitializeComponent();
TheFieldsetContentPresenter.DataContext = this;
FieldsetTitleTextBlock.DataContext = this;
}
First you need initialize the components, then you can set the DataContext to them.
You need to create CustomControl and put use TemplateBinding rather than using Binding. Then you will be able to use this control from somewhere else and I will fix your issue.
Template Binding and Custom control in Silverlight
Cheers!
Vinod
As the title says, I want to bind a property from my ViewModel to a nested UserControl in the corresponding view.
I cant get it work the way I need.
The nested UserControl is nothing more than a DatePicker and a DropDown for the hours. How can I tell the DatePicker to choose the date propagated by the ViewModel as its selected date?
I tried nearly everything and now I'm not far away from jumping outside the window.
As you can see any help is appreciated ;)
Now to the code so far: DateTimePicker.xaml.cs (CodeBehind)
public partial class DateTimePicker
{
public static DependencyProperty SelectedDateValueProperty = DependencyProperty.Register("SelectedDateValue", typeof (DateTime), typeof (DateTimePicker), new FrameworkPropertyMetadata(default(DateTime), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnPropertyChangedCallback));
private static void OnPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
{
Debug.WriteLine("Wohoo. I'm here and still debugging...");
}
public DateTimePicker()
{
InitializeComponent();
DataContext = this;
var times = GetTimes();
Times.ItemsSource = times;
Times.SelectedItem = times.First();
}
public DateTime SelectedDateValue
{
get { return (DateTime) GetValue(SelectedDateValueProperty); }
set { SetValue(SelectedDateValueProperty, value); }
}
}
The nested UserControl (DateTimePicker.xaml):
<UserControl x:Class="Framework.Controls.DateTimePicker"
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="30" d:DesignWidth="200"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<DatePicker HorizontalAlignment="Left" Name="DatePickerCalendar" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Center" SelectedDate="{Binding SelectedDateValue}" />
<ComboBox Grid.Column="1" VerticalAlignment="Center" Name="Times" DisplayMemberPath="Name" />
</Grid>
And, last but not least: The View which has the nested UserControl (View.xaml)
<CustomControls:DateTimePicker SelectedDateValue="{Binding LocalRegistrationStartDate, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
Hope the problem is clear and anybody can help me or get the point at what i am doing wrong here.
Using:
"{Binding SelectedDateValue}"
tells WPF "Hey check my DataContext for a property called SelectedDateValue".
What you want is, to get the Property from your user control.
The easiest way is to give your user control a name like:
<UserControl x:Name="myControl"/>
and then modify your binding to :
"{Binding ElementName=myControl, Path=SelectedDateValue}"
The usual way WPF controls are implemented is to use a template rather than defining the control as direct content, like you're doing here. By using a Template, you have access to TemplateBinding, allowing you to easily bind your control properties. See the Control Customization MSDN page.
<ControlTemplate TargetType="{x:Type local:DateTimePicker>
...
<DatePicker SelectedDate="{TemplateBinding SelectedDateValue}" />
...
</ControlTemplate>
What is the proper way to implement Custom Properties in Silverlight UserControls?
Every "Page" in Silverlight is technically a UserControl (they are derived from the UserControl class). When I say UserControl here, I mean a Custom UserControl that will be used inside many different pages in many different scenarios (similar to an ASP.NET UserControl).
I would like the Custom UserControl to support Binding and not rely on the Name of the Property it is binding to, to always be the same. Instead, I would like the UserControl itself to have a property that the Controls inside the UserControl bind to, and the ViewModels outside the UserControl also bind to. (please see the example below)
Binding within the UserControl works, Binding within the MainPage works, The Binding I set up between the MainPage and the UserControl does not work. Specifically this line:
<myUserControls:MyCustomUserControl x:Name="MyCustomControl2"
SelectedText="{Binding MainPageSelectedText, Mode=TwoWay}"
Width="200" Height="50" />
example output:
MainPage.xaml
<UserControl x:Class="SilverlightCustomUserControl.MainPage"
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:myUserControls="clr-namespace:SilverlightCustomUserControl"
mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Canvas x:Name="LayoutRoot">
<StackPanel Orientation="Vertical">
<TextBlock Text="UserControl Binding:" Width="200"></TextBlock>
<myUserControls:MyCustomUserControl x:Name="MyCustomControl2" SelectedText="{Binding MainPageSelectedText, Mode=TwoWay}" Width="200" Height="50" />
<TextBlock Text="MainPage Binding:" Width="200"></TextBlock>
<TextBox Text="{Binding MainPageSelectedText, Mode=TwoWay}" Width="200"></TextBox>
<Border BorderBrush="Black" BorderThickness="1">
<TextBlock Text="{Binding MainPageSelectedText}" Width="200" Height="24"></TextBlock>
</Border>
</StackPanel>
</Canvas>
</UserControl>
MainPage.xaml.cs
namespace SilverlightCustomUserControl
{
public partial class MainPage : UserControl, INotifyPropertyChanged
{
//NOTE: would probably be in a ViewModel
public string MainPageSelectedText
{
get { return _MainPageSelectedText; }
set
{
string myValue = value ?? String.Empty;
if (_MainPageSelectedText != myValue)
{
_MainPageSelectedText = value;
OnPropertyChanged("MainPageSelectedText");
}
}
}
private string _MainPageSelectedText;
public MainPage()
{
InitializeComponent();
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string name)
{
PropertyChangedEventHandler ph = this.PropertyChanged;
if (ph != null)
ph(this, new PropertyChangedEventArgs(name));
}
#endregion
}
}
MyCustomUserControl.xaml
<UserControl
x:Class="SilverlightCustomUserControl.MyCustomUserControl"
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"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<StackPanel>
<TextBox Text="{Binding SelectedText, Mode=TwoWay}" />
<Border BorderBrush="Black" BorderThickness="1">
<TextBlock Text="{Binding SelectedText}" Height="24"></TextBlock>
</Border>
</StackPanel>
</Grid>
</UserControl>
MyCustomUserControl.xaml.cs
namespace SilverlightCustomUserControl
{
public partial class MyCustomUserControl : UserControl
{
public string SelectedText
{
get { return (string)GetValue(SelectedTextProperty); }
set { SetValue(SelectedTextProperty, value); }
}
public static readonly DependencyProperty SelectedTextProperty =
DependencyProperty.Register("SelectedText", typeof(string), typeof(MyCustomUserControl), new PropertyMetadata("", SelectedText_PropertyChangedCallback));
public MyCustomUserControl()
{
InitializeComponent();
}
private static void SelectedText_PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
//empty
}
}
}
References (how I got this far):
use DependencyPropertys:
http://geekswithblogs.net/thibbard/archive/2008/04/22/wpf-custom-control-dependency-property-gotcha.aspx
use DependencyPropertys, add x:Name to your UserControl - add Binding with ElementName, set Custom property again in the PropertyChangedCallback method:
Setting Custom Properties in UserControl via DataBinding
don't use custom properties, rely on underlying datacontext names (I do not like this solution):
wpf trouble using dependency properties in a UserControl
I understand it as the reason your control is not receiving the new value from the maim page is that you are setting the DataContext of the control. If you hadn't then the control's DataContext will be inherited from its parent, the main page in this case.
To get this to work I removed you control's DataContext setting, added an x:Name to each control and set the binding in the constructor of the control using the [name].SetBinding method.
I did the binding in the ctor as I couldn't figure out a way of setting the Source property of the declarative binding in the xaml to Self. i.e. {Binding SelectedText, Mode=TwoWay, Source=[Self here some how]}. I did try using RelativeSource={RelativeSource Self} with no joy.
NOTE: All this is SL3.
The Issue was the UserControl was throwing a DataBinding error (visible in the Output window while debugging)
Because The UserControl's DataContext was set to "Self" in its own xaml, it was looking for the MainPageSelectedText within its own context (it was not looking for the MainPageSelectedText within the "MainPage" which is where you might think it would look, because when you are physically writing/looking at the code that is what is in "context")
I was able to get this "working" by setting the Binding in the code behind. Setting the binding in the code behind is the only way to set the UserControl itself as the "Source" of the binding. But this only works if the Binding is TwoWay. OneWay binding will break this code. A better solution altogether would be to create a Silverlight Control, not a UserControl.
See Also:
http://social.msdn.microsoft.com/Forums/en-US/silverlightcontrols/thread/052a2b67-20fc-4f6a-84db-07c85ceb3303
http://msdn.microsoft.com/en-us/library/cc278064%28VS.95%29.aspx
MyCustomUserControl.xaml
<UserControl
x:Class="SilverlightCustomUserControl.MyCustomUserControl"
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">
<Grid>
<StackPanel>
<TextBox x:Name="UserControlTextBox" />
<Border BorderBrush="Black" BorderThickness="1">
<TextBlock x:Name="UserControlTextBlock" Height="24"></TextBlock>
</Border>
</StackPanel>
</Grid>
</UserControl>
MyCustomUserControl.xaml.cs
namespace SilverlightCustomUserControl
{
public partial class MyCustomUserControl : UserControl
{
public string SelectedText
{
get { return (string)GetValue(SelectedTextProperty); }
set { SetValue(SelectedTextProperty, value); }
}
public static readonly DependencyProperty SelectedTextProperty =
DependencyProperty.Register("SelectedText", typeof(string), typeof(MyCustomUserControl), new PropertyMetadata("", SelectedText_PropertyChangedCallback));
public MyCustomUserControl()
{
InitializeComponent();
//SEE HERE
UserControlTextBox.SetBinding(TextBox.TextProperty, new Binding() { Source = this, Path = new PropertyPath("SelectedText"), Mode = BindingMode.TwoWay });
UserControlTextBlock.SetBinding(TextBlock.TextProperty, new Binding() { Source = this, Path = new PropertyPath("SelectedText") });
//SEE HERE
}
private static void SelectedText_PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
//empty
}
}
}
Instead of binding data context to self, you can set the binding in xaml by adding an x:Name for the user control and then binding in the user control xaml follows:
<UserControl
x:Class="SilverlightCustomUserControl.MyCustomUserControl"
x:Name="myUserControl
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">
<Grid>
<StackPanel>
<TextBox Text="{Binding SelectedText, ElementName=myUserContol, Mode=TwoWay}" />
<Border BorderBrush="Black" BorderThickness="1">
<TextBlock Text="{Binding SelectedText,ElementName=myUserControl}" Height="24"></TextBlock>
</Border>
</StackPanel>
</Grid>
</UserControl>
Im having some problems with binding in wpf/xaml. Have this simple file:
<Window x:Class="test.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<TextBlock Height="21" Foreground="Black" Margin="74,98,84,0" Name="textBlock1" VerticalAlignment="Top" Text="{Binding MyText}" />
</Grid>
</Window>
Where i want to bind the content of the textblock to my property "MyText". My code looks like this:
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
public string MyText
{
get { return "This is a test"; }
}
}
All in all very simple, but when i start the textblock has no content - howcome?
you need an element name in your binding:
<Window ... x:Name="ThisWindow"...>
<TextBlock ... Text="{Binding MyText, ElementName=ThisWindow}" />
If I'm remembering my WPF binding syntax correctly, I believe your binding expression should read Text="{Binding Path=MyText}"
There are a number of ways to accomplish this. Probably the easiest for something as simple as this form is:
public Window1()
{
InitializeComponent();
this.DataContext = this;
}
I've create user control like this:
public partial class View
{
public View()
{
InitializeComponent();
}
public static DependencyProperty NameProperty = DependencyProperty.Register("Name", typeof(string), typeof(TeaserView) );
public string Name
{
get { return (string)GetValue(NameProperty); }
set { SetValue(NameProperty, value); }
}
}
XAML:
<UserControl x:Class="Controls.View"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="200" Width="164">
<Grid VerticalAlignment="Stretch"
x:Name="Preview">
<Label Height="28" Content="{Binding ElementName=Preview, Path=Name}" Background="LightYellow" x:Name="name" VerticalAlignment="Top" ></Label>
</Grid>
</UserControl>
and use it in Window1 simply in XAML:
<controls:View Height="200" Name="View1" Width="164" />
and I try set the Content in C# (Name property in this sample) but it does'n work, label's content is still empty. (All refereces, etc. are good) What's wrong?
Your code is wrong. You bind to Grid.Name property, which is "Preview", not to View.Name.
I really encourage you to go read from A to Z "DataBinding Overview" on MSDN. It worth your time, trust me :). In fact whole "Windows Presentation Foundation" section would be worth your attention.
As for your code, the following will work:
<UserControl x:Class="WpfApplication5.View"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300"
Width="300"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<Label Height="28"
Content="{Binding Path=Name}"
Background="LightYellow"
VerticalAlignment="Top"/>
</Grid>
</UserControl>
But are you sure you want to hide "Name" property from parents?
Have you set the datacontext on the user control? Try setting it to point to its own codebehind:
DataContext="{Binding RelativeSource={RelativeSource Self}}"
I've put the Name property just as sample. I'm trying to set Label Content in Window1.xaml.cs like:
View1.Name = "Casablanca";
Try the following binding, it should work:
<Label Content="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:View}}, Path=Name}" />
You should also define a xmlns:local="whatever_path_you_have" on the top of the file.
I also suggest renaming "Name" DP to something else to avoid name collusion.
Copied your exact code and it works fine.
However, it's not doing what you're probably expecting it to do. You're setting the source of the binding to the Grid instance. Therefore, the Name property will yield "Preview". The Name property you've defined in your UserControl is ignored because there's already a Name property on UserControl.