Simple Dependency Property and UserControl issues in C# - c#

My end goal is to expose the Text value of a TextBox that I have in a UserControl, from the UserControl's call in XAML.
<my:UserControl SetCustomText="Blah blah this is variable">
would render the UserControl with that TextBox's text filed in.
I've been working at it using various examples but I always end up with "The Property SetCustomText was not found in type UserControl"

Example of how you can do this:
<UserControl x:Class="Test.UserControls.MyUserControl1"
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"
Name="control">
<Grid>
<!-- Text is being bound to outward representative property -->
<TextBox Text="{Binding MyTextProperty, ElementName=control}"/>
</Grid>
</UserControl>
public partial class MyUserControl1 : UserControl
{
// The dependency property which will be accessible on the UserControl
public static readonly DependencyProperty MyTextPropertyProperty =
DependencyProperty.Register("MyTextProperty", typeof(string), typeof(MyUserControl1), new UIPropertyMetadata(String.Empty));
public string MyTextProperty
{
get { return (string)GetValue(MyTextPropertyProperty); }
set { SetValue(MyTextPropertyProperty, value); }
}
public MyUserControl1()
{
InitializeComponent();
}
}
<uc:MyUserControl1 MyTextProperty="Text goes here"/>

Related

Can I use xaml binging without ui? without derive from control?

I want to use xaml to build my workflow like this to split the workflow design and functions.
<Command x:Class="MyCommand">
<Step1 Name="">
<Step2 />
</Step1>
</Command/>
it works.
but when I want to get a value may be updated, i must write a event:
<Command x:Class="MyCommand">
<Step1 GetName="OnGetName">
<Step2 />
</Step1>
</Command/>
void OnGetName(out string name){name = "xxx";}
I think wpf's binding is very well for me ,but sine there are no window, my classes are not inherit from control, It cannot work, event I make my classes inherit from DependencyObject.
Is there any way to import a binding like method?
I update my question as maybe a complete new question.
My real request is use xaml binding without window.
at beginning, I don't want to inherit from Control or FrameworkElement. bug I find it is impossible.
now I update my code to inherit from FrameworkElement, it can work by write binding, but event not with xaml.
public class Command : FrameworkElement
{
public static readonly DependencyProperty Test1Property = DependencyProperty.Register(
nameof(Test1), typeof(string), typeof(UserControl1), new PropertyMetadata(default(string)));
public string Test1
{
get { return (string)GetValue(Test1Property); }
set { SetValue(Test1Property, value); }
}
public static readonly DependencyProperty Test2Property = DependencyProperty.Register(
nameof(Test2), typeof(string), typeof(UserControl1), new PropertyMetadata(default(string)));
public string Test2
{
get { return (string)GetValue(Test2Property); }
set { SetValue(Test2Property, value); }
}
}
I add a window:
<Window x:Class="WpfApp2.MainWindow"
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:local="clr-namespace:WpfApp2"
mc:Ignorable="d" x:Name="Main"
DataContext="{x:Reference Main}"
Title="MainWindow" Height="450" Width="800">
<Grid>
<local:UserControl1 x:Name="Control" Test1="{Binding TestStr, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"></local:UserControl1>
</Grid>
</Window>
and init the Test2 binding by code:
public MainWindow()
{
InitializeComponent();
var binding = new Binding("TestStr")
{
Source = this,
};
BindingOperations.SetBinding(Control, UserControl1.Test2Property, binding);
TestStr = "XXS";
MessageBox.Show($"ONLoad: Test1: {Control.Test1}, Test2: {Control.Test2}");
}
then if I new the MainWindow, without Show(), I get the MessageBox show
Test1:, Test2:XXS
I want to find a way to make the xaml binding work before show()!

Specify Binding of DependencyProperty in UserControl itself

Following up on my previous question (Change brushes based on ViewModel property)
In my UserControl I have have a DependencyObject. I want to bind that object to a property of my ViewModel. In this case a CarViewModel, property name is Status and returns an enum value.
public partial class CarView : UserControl
{
public CarStatus Status
{
get { return (CarStatus)GetValue(CarStatusProperty); }
set { SetValue(CarStatusProperty, value); }
}
public static readonly DependencyProperty CarStatusProperty =
DependencyProperty.Register("Status", typeof(CarStatus), typeof(CarView), new PropertyMetadata(OnStatusChanged));
private static void OnStatusChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
var control = (CarView)obj;
control.LoadThemeResources((CarStatus)e.NewValue == CarStatus.Sold);
}
public void LoadThemeResources(bool isSold)
{
// change some brushes
}
}
<UserControl x:Class="MySolution.Views.CarView"
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:views="clr-MySolution.Views"
mc:Ignorable="d"
views:CarView.Status="{Binding Status}">
<UserControl.Resources>
</UserControl.Resources>
<Grid>
<TextBlock Text="{Binding Brand}"FontSize="22" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
<UserControl
Where do I need to specify this binding? In the root of the UserControl it gives an error:
The attachable property 'Status' was not found in type 'CarView'
In my MainWindow I bind the CarView using a ContentControl:
<ContentControl
Content="{Binding CurrentCar}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type viewmodel:CarViewModel}">
<views:CarView />
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
My ViewModel:
[ImplementPropertyChanged]
public class CarViewModel
{
public Car Car { get; private set; }
public CarStatus Status
{
get
{
if (_sold) return CarStatus.Sold;
return CarStatus.NotSold;
}
}
}
your binding isn't well written. instead of writing views:CarView.Status="{Binding Status}" you should write only Status="{Binding Status}"
It seems that your Control is binding to itself.
Status is looked for in CarView.
You should have a line of code in your control CodeBehind like :
this.DataContext = new ViewModelObjectWithStatusPropertyToBindFrom();
Regards

DependencyProperty Silverlight UserControl

I have read through a few articles on this and I can't see what im doing wrong here could anyone help :)
I have a UserControl called CreateRuleItemView I want to add a Dependency Property on here that I can bind my ViewModel too. So far I have.
public partial class CreateRuleItemView : UserControl
{
public CreateRuleItemView()
{
InitializeComponent();
}
public Boolean ShowEditTablePopup
{
get
{
return (Boolean)this.GetValue(ShowEditTablePopupProperty);
}
set
{
this.SetValue(ShowEditTablePopupProperty, value);
}
}
public static readonly DependencyProperty ShowEditTablePopupProperty = DependencyProperty.Register("ShowEditTablePopup", typeof(Boolean), typeof(CreateRuleItemView), new PropertyMetadata(null, OnShowEditTablePopupChanged));
private static void OnShowEditTablePopupChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
}
}
}
If I then try to access the property in the User Control Xaml I get:
<UserControl x:Class="Views.Setup.CreateRuleItemView"
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"
d:DataContext="{d:DesignInstance Type=vm:CreateRuleItemViewModel, IsDesignTimeCreatable=False}"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400" ShowEditTablePopup="{Binding DataContext.ShowEditTablePopup}" >
Error 1 The member "ShowEditTablePopup" is not recognized or is not accessible.
Error 3 The property 'ShowEditTablePopup' does not exist on the type 'UserControl'
Error 2 The property 'ShowEditTablePopup' was not found in type 'UserControl'.
Edit 1:
Ok Managed to get around this by adding the binding in the code behind on my Main window where i setup my view.
Setup.CreateRuleItemView v = new Setup.CreateRuleItemView();
BindingOperations.SetBinding(v, CreateRuleItemView.EditTablePopupProperty, new Binding("EditTablePopup"));
You won't be able to achieve this with a UserControl (I've just tried replacing the <UserControl... partial declaration in XAML with <local:CreateRuleItemView when recreating the code locally, but this results in a circular reference and thus won't compile/will potentially result in a XamlParseException). I'd write a control inheriting from ContentControl to which you can add the property and template it instead (I did this with WPF so the namespaces may differ, otherwise the code will work):
using System;
using System.Windows;
using System.Windows.Controls;
namespace DepPropTest
{
/// <summary>
/// Description of CreateRuleItemView.
/// </summary>
public class CreateRuleItemView : ContentControl
{
public CreateRuleItemView()
{
}
public static readonly DependencyProperty ShowEditTablePopupProperty =
DependencyProperty.Register("ShowEditTablePopup", typeof (bool), typeof (CreateRuleItemView), new PropertyMetadata());
public bool ShowEditTablePopup
{
get { return (bool) GetValue(ShowEditTablePopupProperty); }
set { SetValue(ShowEditTablePopupProperty, value); }
}
}
}
Then you can use it as follows (this example uses WPF by the way, hence Window being the parent control):
<Window x:Class="DepPropTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DepPropTest"
Title="DepPropTest" Height="300" Width="300">
<local:CreateRuleItemView Width="300"
Height="300"
ShowEditTablePopup="True">
<local:CreateRuleItemView.Template>
<ControlTemplate>
<!-- define your control's visual appearance... -->
</ControlTemplate>
</local:CreateRuleItemView.Template>
<TextBox Text="Some content for your view" />
</local:CreateRuleItemView>
</Window>

How to bind a property from my usercontrol content control to a property?

I have a UserControl like this:
<UserControl x:Class="MySample.customtextbox"
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="20" d:DesignWidth="300">
<Grid>
<TextBox x:Name="Ytextbox" Background="Yellow"/>
</Grid>
</UserControl>
I want use my control in mvvm pattern ...i want that i can bind a property in my viewmodel to Ytextbox Text Property
<CT:customtextbox ?(Ytextbox)Text ="{binding mypropertyinviewmodel}"/>
...how can I do it?
You should create a property on the UserControl and bind that internally to the TextBox's text.
i.e.
<UserControl Name="control" ...>
<!-- ... -->
<TextBox Text="{Binding Text, ElementName=control}"
Background="Yellow"/>
public class customtextbox : UserControl
{
public static readonly DependencyProperty TextProperty =
TextBox.TextProperty.AddOwner(typeof(customtextbox));
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
}
Usage:
<CT:customtextbox Text="{Binding mypropertyinviewmodel}"/>
(Do not set the DataContext in the UserControl to itself unless you want all external bindings which expect the DataContext to be inherited to fail, use ElementName or RelativeSource for internal bindings)

Updating UserControl children in DependencyProperty setter not working

I have a UserControl in my Silverlight application and for some reason, the DependencyProperty of a UserControl is not set if I bind it to a value in the view model. I spent several hours of debugging in a trial-and-error fashion now and I'm all out of ideas what to try next.
I can reproduce the issue in a new Silverlight project with
MainPage.xaml
<UserControl x:Class="SilverlightApplication1.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:local="clr-namespace:SilverlightApplication1"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<StackPanel>
<local:MyCtrl HeaderText="{Binding HeaderText}"/>
<TextBlock Text="{Binding HeaderText}"/>
</StackPanel>
</Grid>
</UserControl>
MainPage.xaml.cs
using System.Windows.Controls;
namespace SilverlightApplication1
{
public class Vm
{
public string HeaderText
{ get; set; }
}
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
DataContext = new Vm() { HeaderText = "My Header" };
}
}
}
MyCtrl.xaml (added as new "Silverlight User Control")
<UserControl x:Class="SilverlightApplication1.MyCtrl"
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"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<TextBlock x:Name="txtHeader" />
</Grid>
</UserControl>
MyCtrl.xaml.cs
using System.Windows;
using System.Windows.Controls;
namespace SilverlightApplication1
{
public partial class MyCtrl : UserControl
{
public MyCtrl()
{
InitializeComponent();
}
public static readonly DependencyProperty HeaderTextProperty = DependencyProperty.Register(
"HeaderText", typeof(string), typeof(MyCtrl), null);
public string HeaderText
{
get { return (string)GetValue(HeaderTextProperty); }
set
{
// NEVER CALLED
SetValue(HeaderTextProperty, value);
this.txtHeader.Text = value;
}
}
}
}
The rest of the project is used "as is", i.e. no compiler options were changed and the server part is also left "as is".
Observations:
I see that the getter of Vm.HeaderText is called during a binding
operation but the setter of the DependencyProperty MyCtrl.HeaderText is never called.
The TextBlock in MainPage below the custom control displays the bound value correctly.
There are no compiler warnings.
There are no exceptions thrown.
There are no debug outputs while the application runs.
This feels like something important is silently failing where it shouldn't.
Maybe I can shed some light on your observations and assumptions:
You can update child controls inside a DependencyProperty setter. Call your setter and see for yourself, the update will be performed. You falsely assume the binding engine is obliged to call your setter. Well, it just calls SetValue(HeaderTextProperty, newValue); on your control, no need to call the setter.
Your observation is specified behaviour.
As you figured out, the right way to do it is to use a propertyChanged callback.
The property getter on your viewmodel Vm.HeaderText is called by the binding engine, because your viewmodel is no DependencyObject and HeaderText is no DependencyProperty so there is no SetValue(...) and no GetValue(...)
You can't see any compiler warnings or exceptions, nor is anything silently failing, because there is nothing wrong with your scenario.
Well, seems like you cannot update the child controls inside a DependencyProperty setter (would be interesting to know why and if this is specified behaviour...)
Using this instead works:
public static readonly DependencyProperty HeaderTextProperty = DependencyProperty.Register(
"HeaderText", typeof(string), typeof(MyCtrl), new PropertyMetaData(OnHeaderTextChanged));
public string HeaderText
{
get { return (string)GetValue(HeaderTextProperty); }
set { SetValue(HeaderTextProperty, value); }
}
private static void OnHeaderTextChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
var ctrl = d as MyCtrl;
ctrl.txtHeader.Text = (string)e.NewValue;
}

Categories