I have an User control. That UserControl have some functionalities. I have called this usercontrol in my Common Resource Directory file. I am Inherit this Resource Directory page in all pages. This enables my user control in all my pages. what i want is, I want this usercontrol for Some particular page which i can set. This is my code.
Resource Directory file:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:l="clr-namespace:UserControls">
<!-- Navigation AppBar -->
<l:NavigationAppBarUserControl
Grid.Row="1" Grid.Column="0" Width="100"
HorizontalAlignment="Left" Visibility="Visible" />
</ResourceDictionary>
Window1.xaml:
<src:WindowBase x:Class=""
xmlns:src="clr-namespace:ProjectOne"
Title="Window1">
<Grid>
//some functions...
</Grid>
</src:WindowBase>
This will enable my user control. But this page, i want to hide my user conrol. But without removing (src:WindowBase).. how can i hide the UserControl here? Any help would be appriciated. Thanks in advance..
In WindowBase class create a property of type Visibility and bind the Visisbility of UserControl to it.
WindowBase
public class WindowBase : Window
{
public WindowBase(Visibility ucVisibility)
{
UCVisibility = ucVisibility;
}
public WindowBase() : this(Visibility.Visible) { }
public Visibility UCVisibility { get; set; }
//other stuff
}
UC binding
<l:NavigationAppBarUserControl
Grid.Row="1" Grid.Column="0" Width="100"
HorizontalAlignment="Left"
Visibility="{Binding UCVisibility, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}" />
Now where you do not want it to show send Visibility.Collapsed in base constructor.
public partial class Window3 : WindowBase
{
public Window3():base(Visibility.Collapsed)
{
InitializeComponent();
}
}
I hope this will help.
Related
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>
I have a ParentView that contains a childView
<UserControl ... x:Name="MyParentView">
<Grid>
<sdk:TabControl Name="ContactTabControl">
<sdk:TabItem Header="Contact" Name="CustomerTabItem">
<Grid>
<Views:CustomerView/>
</Grid>
</sdk:TabItem>
</sdk:TabControl>
</Grid>
</UserControl>
Within my CustomerView I would like to bind the Firstname textbox to Parent's DataContext. I have tried this inside the CustomerView:
<TextBox Text={Binding ElementName=MyParentView, Path=DataContext.Firstname} />
I have the feeling that CustomerView won't be able to see its parent at all, hence the ElementName "MyParentView" would never be found.
What is your advice on this?
I've done a similar thing but I just bound it directly to Path considering that if I don't give it explicit data context, it will lookup the hierarchy and find one that matches.
So this should get you what you want:
<TextBox Text={Binding Path=FirstName} />
if you need to specify explicit datacontext you can always do:
<Grid>
<Views:CustomerView DataContext={"CustomContextHere"}/>
</Grid>
An alternative solution to Maverik's is :
1 Define a dependency property in your customer view :
public partial class CustomerView : UserControl
{
public CustomerView()
{
InitializeComponent();
}
public static DependencyProperty FirstNameProperty =
DependencyProperty.Register("FirstName", typeof(string), typeof(CustomerView), new PropertyMetadata(string.Empty, CustomerView.FirstNameChanged));
public string FirstName
{
get { return (string)GetValue(FirstNameProperty); }
set { SetValue(FirstNameProperty, value); }
}
private static void FirstNameChanged(object sender, DependencyPropertyChangedEventArgs e)
{ }
}
2 Modify the customer view's textbox to bind to this dependency property (note the element binding "this")
<UserControl x:Class="SLApp.CustomerView"
x:Name="this"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<Grid x:Name="LayoutRoot" Background="White">
<TextBox Text="{Binding Path=FirstName, ElementName=this, Mode=TwoWay}"/>
</Grid> </UserControl>
3 Modify the parent view and bind it's DataContext to the new dependency property
<sdk:TabControl Name="ContactTabControl">
<sdk:TabItem Header="Contact" Name="CustomerTabItem">
<Grid>
<local:CustomerView FirstName="{Binding ElementName=ContactTabControl, Path=DataContext}"/>
</Grid>
</sdk:TabItem>
</sdk:TabControl>
4 Set the parent's DataContext
public partial class MyParentView : UserControl
{
public MyParentView()
{
InitializeComponent();
ContactTabControl.DataContext = "A name";
}
}
Voila' it works. Not the most elegant solution but it gets the job done for your scenario
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.
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>
Is it possible to bind an Event in a Silverlight DataTemplate? If so, what is the best way to do it?
For example, say you've created a DataTemplate that has a Button in it, like this:
<UserControl.Resources>
<DataTemplate x:Key="MyDataTemplate" >
<Grid>
<Button Content="{Binding ButtonText}" Margin="4" />
</Grid>
</DataTemplate>
</UserControl.Resources>
Then, you apply it to a ListBox ItemTemplate, like this:
<Grid x:Name="LayoutRoot" Background="White">
<ListBox x:Name="lbListBox" ItemTemplate="{StaticResource MyDataTemplate}" />
</Grid>
If you set the ListBox's ItemSource to a list of objects of the class:
public class MyDataClass
{
public string ButtonText{ get; set; }
}
How then do you catch the button click from each button from the DataTemplate in the list? Can you use binding to bind the Click event to a method in "MyButtonClass", like this:
<UserControl.Resources>
<DataTemplate x:Key="MyDataTemplate" >
<Grid>
<Button Click="{Binding OnItemButtonClick}" Content="{Binding ButtonText}" Margin="4" />
</Grid>
</DataTemplate>
</UserControl.Resources>
Would this work? If so, what should I put in the "MyDataClass" to catch the event?
Thanks,
Jeff
There are a couple of options.
One. make a custom control that is bound the data object for that row. On that custom control add the handler for the bound object.
I dont think your binding on the click will work. Sans the Binding Statment and just declare your click to a string.
Add the handler on the page where the control is housed.
Keep in mind that if you bind this way you will only be able to work with the sender of that item (button) and it's properties. If you need to get at specific attributes on an object you maybe better off pursuing the first option.
Small Example demonstrating the functionality by adding 10 buttons to a list box with click events. HTH
DataTemplate XAML
<UserControl.Resources>
<DataTemplate x:Name="MyDataTemplate">
<Grid>
<Button Click="Button_Click" Content="{Binding ItemText}"/>
</Grid>
</DataTemplate>
</UserControl.Resources>
ListBox XAML
<ListBox x:Name="ListBoxThingee" ItemTemplate="{StaticResource MyDataTemplate}"/>
Code Behind (I just plugged this all into the page.xaml file
public class MyClass
{
public string ItemText { get; set; }
}
public partial class Page : UserControl
{
ObservableCollection<MyClass> _Items;
public Page()
{
InitializeComponent();
_Items = new ObservableCollection<MyClass>();
for (int i = 0; i < 10; i++)
{
_Items.Add(new MyClass() {ItemText= string.Format("Item - {0}", i)});
}
this.ListBoxThingee.ItemsSource = _Items;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Button _b = sender as Button;
if (_b != null)
{
string _s = _b.Content as string;
MessageBox.Show(_s);
}
}
}
What I would do is create a button that uses the command pattern for click handling. In the .NET 4 framework you can bind commands to those that exist on the view model.