How do you make a custom XAML User Control bindable? - c#

I am making a simple demo to learn how to create a bindable user control. I have created a simple class:
class Person
{
public string firstName;
public string lastName;
public Person(string first, string last)
{
firstName = first;
lastName = last;
}
}
And a very simple user control:
<UserControl x:Class="Example.ExampleHRControl"
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>
<TextBlock x:Name="textFirstName"></TextBlock>
<TextBlock x:Name="textLastName"></TextBlock>
</Grid>
</UserControl>
What I would like to know is what do I need to do in order to be able to use the user control in context like a normal control. I can add this to the MainWindow:
<local:ExampleHRControl x:Name="Hr1"></local:ExampleHRControl>
and then I can address it through code behind and add the value:
Hr1.textFirstName.Text = "John";
Hr1.textLasttName.Text = "Doe";
I would prefer to be able to create an instance of the class Person and simply bind the control on the main window to the Person class.

A couple things you need to do to make this work.
In your code-behind, add a dependency property for the Person object you want your control to know about:
public static readonly DependencyProperty PersonProperty =
DependencyProperty.Register("Person", typeof(Person),
typeof(ExampleHRControl));
public Person Person
{
get { return (Person)GetValue(PersonProperty); }
set { SetValue(PersonProperty, value); }
}
In your XAML, set up your code-behind as your data context and add the binding to your person object:
<UserControl x:Class="Example.ExampleHRControl"
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"
x:Name="This">
<Grid>
<TextBlock x:Name="{Binding Path=Person.FirstName, ElementName=This}"/>
<TextBlock x:Name="{Binding Path=Person.LastName, ElementName=This}"/>
</Grid>
</UserControl>
Now, whenever the Person property is set, your control will update itself with the First and Last names that are associated to the Person.

what you want to to called Dependancy Property you can bind to it from xaml.
1-create the field
public static readonly DependencyProperty FirstNameProperty =
DependencyProperty.Register(
"FirstName", typeof(Strin),
2-create the property
public String FirstName
{
get { return (String)GetValue(FirstNameProperty); }
set { SetValue(FirstNameProperty, value); }
}
3- you can use it in the XAML to bind it or just use it
<local:YourControlName FirstName="john"/>
<local:YourControlName FirstName="{Binding MyFirstName}"/>
use Resharper will help you to make a clean code and have very powerfull IntelliSense

Related

Can't access public property on user control wpf c#

I'm trying to access a public property on a user control but I am getting this message. I don't think I would need to initialize the user control right? When I try to access the public property DirectorySetter.DirectoryPath I would get this message:
An object reference is required for the non-static field, method, or
property 'DirectorySetter.DirectoryPath'
Here is my user control code-behind:
public partial class DirectorySetter : UserControl
{
public DirectorySetter()
{
InitializeComponent();
}
public string DirectoryPath
{
get
{
return txtDirectoryPath.Text;
}
set
{
txtDirectoryPath.Text = value;
}
}
}
Here is the xaml that uses the user control:
<Page
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:local="clr-namespace:PhotoOrganizer.Pages"
xmlns:UserControls="clr-namespace:PhotoOrganizer.UserControls" x:Class="PhotoOrganizer.Pages.PhotoDirectoryPath"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Title="PhotoDirectoryPath">
<Grid>
<TextBlock HorizontalAlignment="Left" Margin="69,91,0,0" TextWrapping="Wrap" Text="Set your photo directory path" VerticalAlignment="Top"/>
<UserControls:DirectorySetter HorizontalAlignment="Left" Margin="22,135,0,0" VerticalAlignment="Top"/>
<Button Name="btnSave" Content="Save" HorizontalAlignment="Left" Margin="155,178,0,0" VerticalAlignment="Top" Width="75" Click="btnSave_Click"/>
</Grid>
</Page>
Any suggestion or help would be great!
You didn't post the code where there error actually happens, where you try to access that "public property"
So I might just guess that you're trying to do something like
DirectorySetter.DirectoryPath = "asd";
which won't work since your class and your property aren't static.
What you can do though, is (xaml):
<UserControls:DirectorySetter x:Name="myUserControl"/>
Code behind:
var s = (myUserControl as DirectorySetter).DirectoryPath ;
If you want to access your Property from xaml and or bind to it, you will need to implement a Dependency Property in your UserControl Class
// Dependency Property
public static readonly DependencyProperty DirectoryPathProperty =
DependencyProperty.Register( "DirectoryPath", typeof(string),
typeof(DirectorySetter), new FrameworkPropertyMetadata(string.Empty));
// .NET Property wrapper
public string DirectoryPath
{
get { return (string)GetValue(DependencyProperty ); }
set { SetValue(DependencyProperty , value); }
}
Additional Resources from Msdn
Dependency properties overview

how to retrieve textbox string form mainpage in uwp?

I am new to UWP.
I have created an app with a MainPage and a UserControl.
I have a TextBox in that UserControl and I want to access its data from my Mainpage.
Can someone suggest a way to do this?
Thanks
While #Peter have a good answer but I think you also can use FieldModifier.
My UserControl is Averieli and my xaml is :
<UserControl
x:Class="Avalonia.Averieli"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Avalonia"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">
<Grid>
<TextBox x:Name="TextBox" x:FieldModifier="public"></TextBox>
</Grid>
</UserControl>
You can see that I add x:FieldModifier="public" in TextBox that can make it can be used in MainPage.
I use the UserControl in MainPage.
<local:Averieli x:Name="Averieli"></local:Averieli>
I also can use the TextBox in the back code.
public MainPage()
{
InitializeComponent();
Averieli.TextBox.Text = "I can use it";
}
In the constructor of the user control, initialise a static global instance of the UserControl class
public UserControl()
{
//Initialise control
}
public static UserControl UserControlInstance
{
get
{
return m_UserControlInstance ?? new UserControl();
}
}
private static UserControl m_UserControlInstance;
And then just access properties of UserControl via the instance
string x = UserControl.UserControlInstance.TextBox.Text;
This is called a singelton by the way, in case you wanted to look it up!

How to set the public variable value from the wpf user control?

I have one dll which contains the wpf user control.
I have one wpf window in another wpf project which contains the above user control in that.
I have two public properties in wpf user control.
I want to set those properties from the wpf window in which wpf user control is added.
I have tried to do it using dependency property as follows :
TestUserControl.xaml :-
<UserControl x:Class="TestDependencyProperty.TestUserControl"
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>
<Label Content="test property" x:Name="lblTestProperty"/>
</Grid>
</UserControl>
TestUserControl.xaml.cs :-
using System.ComponentModel;
using System.Windows;
namespace TestDependencyProperty
{
/// <summary>
/// Interaction logic for TestUserControl.xaml
/// </summary>
public partial class TestUserControl
{
public TestUserControl()
{
InitializeComponent();
SetLabelText();
}
private void SetLabelText()
{
lblTestProperty.Content = TestProperty;
}
public static readonly DependencyProperty TestDependencyProperty =
DependencyProperty.Register("TestProperty",
typeof(string),
typeof(TestUserControl));
[Bindable(true)]
public string TestProperty
{
get
{
return (string)this.GetValue(TestDependencyProperty);
}
set
{
this.SetValue(TestDependencyProperty, value);
}
}
}
MainWindow.xaml :-
<Window x:Class="TestDependencyProperty.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:TestDependencyProperty"
>
<Grid>
<local:TestUserControl x:Name="ucTest" TestProperty="HelloWorld"/>
</Grid>
</Window>
I am expecting a label with content "HelloWorld".
So can anybody tell me how to do it ?
Thanks.
User Control XAML:
<UserControl x:Class="TestDependencyProperty.TestUserControl"
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:local="clr-namespace:WpfApplication3"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Label Content="{Binding TestProperty}" x:Name="lblTestProperty"/>
</Grid>
</UserControl>
User Control Code:
public partial class TestUserControl : UserControl
{
public TestUserControl()
{
InitializeComponent();
}
public static readonly DependencyProperty TestDependencyProperty =
DependencyProperty.Register("TestProperty",
typeof(string),
typeof(TestUserControl));
[Bindable(true)]
public string TestProperty
{
get
{
return (string)this.GetValue(TestDependencyProperty);
}
set
{
this.SetValue(TestDependencyProperty, value);
}
}
}
You do not need SetLabelText();
Window Hosting User Control
<local:TestUserControl TestProperty="Test Text" x:Name="MyNewUserControl" />
in code behind if needed:
MyNewUserControl.TestProperty="New Value";
Dependency Properties have change notification built in to them so once a property is bound to them it will automatically get updated when the property does.

Get hard coded param from WPF UserControl to code behind

I 'm trying to do something really simple: I have a UserControl, where I want to pass a simple string parameter.
WPF MessagePage.xaml
<Page
x:Class="MuchroomPhone.MessagePage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MuchroomPhone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
//...
<PivotItem Header="Nouveaux">
<local:MessageUC MessType="new"/>
</PivotItem>
<PivotItem Header="Lus" >
<local:MessageUC MessType="read"/>
</PivotItem>
<PivotItem Header="Envoyés" >
<local:MessageUC MessType="send"/>
</PivotItem>
<PivotItem Header="Tous" >
<local:MessageUC MessType="all"/>
</PivotItem>
//...
I want to get the MessType from the code behind of the MessageUC.
eg. : I want to get the string "new" in the MessageUC.xaml.cs
I've tried that so far:
MessageUC.xaml
<UserControl
x:Class="MuchroomPhone.MessageUC"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MuchroomPhone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">
//I don't think the content of the UC is important for my issue, but if you wanted to I can give it too.
MessageUC.xaml.cs
public sealed partial class MessageUC : UserControl
{
public string _messType;
public string MessType
{
get{ return _messType;}
set{this._messType = value;}
}
public ObservableCollection<Message> listMessages { get; set; }
public MessageUC()
{
this.InitializeComponent();
Debug.WriteLine(MessType);
this.fetchUserData();
}
But the MessType string is empty...
Any ideas how to achieve that?
PS: I think there should be a way less verbose way for do that, so if you know a "simple" trick, would be great!
Thanks
EDIT: So If I use a simple property, it's should work? Cause I still have null on MessType...
I've also tried with a Dependency Property, and MessType is an empty string.
EDIT 2: I think I understand what is wrong. Actually MessType doesn't exist on MessageUC.xaml. So the code behind can't find it. Perhaps isn it possible to just pass variable to my Page MessagePage.xaml directly to the User Control MessageUC?
all you need is move fetchUserData to loaded event:
public sealed partial class MessageUC : UserControl
{
public string MessType { get; set; }
public MessageUC()
{
InitializeComponent();
Debug.Writeline(MessType); //null
Loaded += MessageUC_Loaded;
}
public void MessageUC_Loaded(object sender, EventArgs e)
{
Debug.Writeline(MessType); //new
this.fetchUserData();
}
}
DependencyProperty is not needed! Your original code doesn't work, because ctor in invoked before the property is set. DependecyProperty does not solve this, but enables databinding, styling, animating of the property.
You only need a DependencyProperty if you want to data bind to it. In your case you can just use a normal property.
This is a set of instructions that should work. However you didn't show the definition of your control so the code below may need some modifications and adjustments.
So start with registering a dependency property:
public static readonly DependencyProperty _messTypeProperty =
DependencyProperty.Register("_messType", typeof(String),
typeof(MessageUC), new FrameworkPropertyMetadata(string.Empty));
public String _messType
{
get { return GetValue(_messTypeProperty).ToString(); }
set { SetValue(_messTypeProperty, value); }
}
Add a name to your control in XAML:
<UserrControl x:Class="myNamespace.MessageUC"
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"
x:Name="MyUserControl">
In the XAML definition of your MessageUC control, in the code where you implement MessType bind it to the property in the code behind. Point to your control using the name you added to the control definition:
MessType="{Binding Path=_messType, ElementName=MyUserControl}"

dependency property to chart

I have a dependency property and i want to present in on a chart.
namespace ViewModels
{
public partial class MyVM: DependencyObject
{
public Double TotalPowerSoFar
{
get { return (Double)GetValue(TotalPowerSoFarProperty); }
set { SetValue(TotalPowerSoFarProperty, value); }
}
// Using a DependencyProperty as the backing store for GroupReadingsBy. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TotalPowerSoFarProperty =
DependencyProperty.Register("TotalPowerSoFar", typeof(Double), typeof(EstimateVM), new UIPropertyMetadata(0.0));
TotalPowerSoFar=5.0;
}
}
I thought i'd do something like that:
<UserControl x:Class="Workspace"
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:DV="clr-namespace:System.Windows.Controls.DataVisualization;assembly=System.Windows.Controls.DataVisualization.Toolkit"
xmlns:DVC="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<DVC:Chart Name="mcChart" Foreground="DarkBlue" Title="Area Chart" LegendTitle="Month Rating" >
<DVC:Chart.Series>
<DVC:ColumnSeries DependentValueBinding ="{Binding EstimatedTotalPower}"/>
</DVC:Chart.Series>
</DVC:Chart>
</Grid>
But from what i understand the binding is wrong.Any help?
First of all, dependency properties make any sense only for DependencyObject descendants, and your view model isn't a DependencyObject.
The second, if you want to extend functionality of the existing dependency object (Chart in your case), you should use attached properties - they could be attached to DO and data bound to your view model.

Categories