Property of WPF CustomControl is not serialized by XamlWriter - c#

We have made a WPF CustomControl which inherits from the TextBox and added a new DependencyProperty "TableName", so we can set there the name of the DataTable to which the control is bound.
The control is generated at runtime and the property TableName p.e. set to "table1".
Then we serialize the Panel which contains the controls (like our CustomControl) to a XAML file like in this article from CodeProject, because we want to serialize the bindings too:
XamlWriter-and-Bindings-Serialization
Unfortunately - instead of properties like Width - our new DependencyProperty is not serialized.
Is there a way to force the XamlWriter to serialize the property?
Thanks in advance!
This is the Definition of the property in the CustomControl called "CustomTextBox":
public static readonly DependencyProperty TableNameProperty = DependencyProperty.Register("TableName", typeof(string), typeof(CustomTextBox));
public string TableName { get; set; }
It's style in the Generic.xaml:
<Style TargetType="{x:Type local:CustomTextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
</Style>

You have provided a CLR property but it doesn't do anything. You need to link it to your DependencyProperty:
public string TableName
{
get { return (string)GetValue(TableNameProperty); }
set { SetValue(TableNameProperty, value); }
}

Related

Conditional background on GridViewRow based on textbox value next to DataGrid

HOW do I pass the value of the TextBox to the StyleSelector so I can return the correct Style?
I want to be able to choose the background of a row conditionally by comparing a property of the object shown in the row with the value of an input control (e.g TextBox).
I made a StyleSelector class containing two styles and a property to contain the value of the TextBox.
public class OutOfBoundsRowStyleSelector : StyleSelector
{
public double FilterValue { get; set; }
public Style DefaultStyle { get; set; }
public Style OutOfBoundsStyle { get; set; }
public override Style SelectStyle(object item, DependencyObject container)
{
// Compare FilterValue to property of item and return the appropriate style here.
return DefaultStyle;
}
}
I added a TextBox and bound the Value to a property in the ViewModel like so.
<TextBox x:Name="txtBoundsFilter" Text="{Binding BoundsFilter}"/>
I filled these styles in xaml & tried to bind the TextBox value to the property in the StyleSelector class.
<Classes:OutOfBoundsRowStyleSelector x:Key="OutOfBoundsRowStyleSelector">
<Classes:OutOfBoundsRowStyleSelector.DefaultStyle>
<Style TargetType="telerik:GridViewRow">
<Setter Property="Background" Value="White"/>
</Style>
</Classes:OutOfBoundsRowStyleSelector.DefaultStyle>
<Classes:OutOfBoundsRowStyleSelector.OutOfBoundsStyle>
<Style TargetType="telerik:GridViewRow">
<Setter Property="Background" Value="Red" />
</Style>
</Classes:OutOfBoundsRowStyleSelector.OutOfBoundsStyle>
<Classes:OutOfBoundsRowStyleSelector.FilterValue>
<Binding Path="BoundsFilter" Mode="TwoWay"/>
</Classes:OutOfBoundsRowStyleSelector.FilterValue>
</Classes:OutOfBoundsRowStyleSelector>
Finally I added the RowStyleSelector to the DataGrid.
<telerik:RadGridView x:Name="dataGrid" ItemsSource="{Binding BatchList} RowStyleSelector="{StaticResource OutOfBoundsRowStyleSelector}" >
Unfortunately, you cannot use a binding like that. I got the following error message:
A 'Binding' cannot be set on the 'FilterValue' property of type 'OutOfBoundsRowStyleSelector'. A 'Binding' can only be set on a DependencyProperty of a DependencyObject.
I added an extra property to the item model. Then whenever I refresh the grid, I fill in the value of the TextBox in each item. This way I can access the value through the item parameter from the GetStyle() method.
This doesn't seem like the most elegant way, but it did the job for me.

How to create a Dependency Property for Binding

I'm working on a "simple" case. I like to create a new custom control which implements a DependencyProperty. In the next step I like to create a binding for updating the properties in both directions. I've builded a simple sample for this case, but the binding doesn't seem to work. I've found a way for updating the DPControl's property by using the FrameworkPropertyMetadata, but I don't know whether it's also a good idea to use the OnPropertyChanged event.
HERE is my sample project:
My control contains simply a Label
<UserControl x:Class="WPF_MVVM_ListBoxMultiSelection.DPControl"
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:WPF_MVVM_ListBoxMultiSelection"
mc:Ignorable="d" Height="84.062" Width="159.641">
<Grid Margin="0,0,229,268">
<Label Content="TEST" x:Name="label" Margin="0,0,-221,-102"/>
</Grid>
</UserControl>
and implement a custom dependency property. Currently, I have also implemented the PropertyChanged method for the FramePropertyMetadata and set in this method the label's content, but I like to get it work in both directions.
public partial class DPControl : UserControl
{
public DPControl()
{
InitializeComponent();
}
public string MyCustomLabelContent
{
get { return (string)GetValue(MyCustomLabelContentProperty);}
set
{
SetValue(MyCustomLabelContentProperty, value);
}
}
private static void OnMyCustomLabelContentPropertyChanged(DependencyObject source,
DependencyPropertyChangedEventArgs e)
{
DPControl control = (DPControl)source;
control.label.Content = e.NewValue;
}
public static readonly DependencyProperty MyCustomLabelContentProperty = DependencyProperty.Register(
"MyCustomLabelContent",
typeof(string),
typeof(DPControl),
new FrameworkPropertyMetadata(null,
OnMyCustomLabelContentPropertyChanged
)
);
I use this control simply in a Window by:
<local:DPControl MyCustomLabelContent="{Binding MyLabelContent, Mode=TwoWay}" Margin="72,201,286,34"/>
MyLabelContent is a property in the ViewModel, which has implemented also the INotifyPropertyChanged interface.
public class ViewModel_MainWindow:NotifyPropertyChanged
{
private string _myLabelContent;
public string MyLabelContent
{
get { return _myLabelContent; }
set { _myLabelContent = value;
RaisePropertyChanged();
}
}...
So how can I get it work: Using the binding feature with my new control on custom properties.
In your UserControl:
<Label
Content="{Binding MyCustomLabelContent, RelativeSource={RelativeSource AncestorType=UserControl}}"
x:Name="label" Margin="0,0,-221,-102"/>
And get rid of that property-changed callback. All you need is the Binding.
I like to get it work in both directions
To make the dependency property two-way by default:
public static readonly DependencyProperty MyCustomLabelContentProperty =
DependencyProperty.Register(
"MyCustomLabelContent",
typeof(string),
typeof(DPControl),
new FrameworkPropertyMetadata(null,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)
);
I omitted the unnecessary property change handler.
It can't usefully be two-way now, because Label.Content can't generate its own value. If you want your UserControl to set the value in its codebehind, that's easy:
MyCustomLabelContent = "Some arbitrary value";
If you did the binding like I showed you, that will update the Label in the UserControl XAML as well as the viewmodel property bound to the UserControl's dependency property.
If you want the XAML to set it, you'll need to
Lastly, this:
Margin="0,0,-221,-102"
Is not a good way to do layout. WPF layout with Grid, StackPanel, etc. is much easier and more robust.

Style vs inline property setting in silverlight with a custom control

I have a custom silverlight control that is pretty much a glorified text box. I have some properties in it I need to be able to set from the XAML in silverlight, so for each property I have created something like this:
public bool UseCustomTooltips
{
get { return _useCustomTooltips; }
set
{
_useCustomTooltips = value;
DoSomeOtherStuff();
}
}
public static readonly DependencyProperty UseCustomTooltipsProperty = DependencyProperty.Register("UseCustomTooltips",
typeof(bool), typeof(MyControl), new PropertyMetadata(false, PropertyChangedCallback));
In the XAML I can create the control and specify a value for that property like this:
<Controls:MyControl UseCustomTooltips="True" />
The control's state is update, my callback is hit, and all is as it should be. However, when I try to specify that state from a style instead of in each instance of the control like this:
<Style x:Key="MyControl" TargetType="Controls:MyControl">
<Setter Property="Foreground" Value="Yellow"/>
<Setter Property="UseCustomTooltips" Value="True"/>
</Style>
<Controls:MyControl Style="{StaticResource MyControl}" />
my custom properties are never set and my callback is never hit even though the inherited property Foreground takes on the value specified in the style. This leads me to assume there is something wrong with the way my dependency property is wired up but everything I've seen so far online tells me I have it correct.
Can anyone point me in the right direction?
Thanks.
That is not the correct way to register a dependency property.
public bool UseCustomTooltips
{
get { return (bool)GetValue(UseCustomTooltipsProperty); }
set { SetValue(UseCustomTooltipsProperty, value); }
}
public static readonly DependencyProperty UseCustomTooltipsProperty =
DependencyProperty.Register("UseCustomTooltips",
typeof(bool),
typeof(MyControl),
new PropertyMetadata(false, new PropertyChangedCallback(MyCallbackMethod)));
Use the propdp snippet, it really is a beautiful thing.

Xaml inside ContentControl and binding to DependencyProperty

I have two questions about developing at Windows Phone:
I want to create custom control and be able to provide some extra XAML inside it. So I use ContentControl with ContentPresenter inside ControlTemplate.
<ContentControl>
<ControlTemplate>
<TextBlock Name="TextBlockControl" Text="Existing controls"/>
<ContentPresenter/>
</ControlTemplate>
</ContentControl>
It worked, but I can't access TextBlockControl inside ControlTemplate from code-behind. FindName always returns null.
Secondly, I want to provide attributes for Control, so I create DependencyProperty like this:
public string CustomText
{
get { return (string)GetValue(CustomTextProperty); }
set
{
SetValue(CustomTextProperty, value);
TextBlockControl.Text = value;
}
}
public static readonly DependencyProperty CustomTextProperty =
DependencyProperty.Register("CustomText", typeof(string), typeof(MyControl), null);
As you can see, I write TextBlockControl.Text = value; to set text for TextBlock inside of my Control. When I set static string - it works
<MyControl CustomText="Static Text"/>
But when I want to use Binding (e.g. for LocalizedStrings resource) - it doesn't work. Am i missing PropertyMeta Callback, or some IPropertyChanged inheritance? I have read tons of StackOverflow questions with the same issue, but nothing answered my questions.
the answer to the first question :
If you créate your custom-control, and you assign a template, you can Access to the elements in that template using :
[TemplatePart(Name = "TextBlockControl", Type = typeof(FrameworkElement))]
You have to put this attribute in order to tools like blend, know that the template for this custom-control has to have a textblock called TextBlockControl.Then from the control's OnApplyTemplate you should get a reference to it whit :
protected override void OnApplyTemplate()
{
_part1 = this.GetTemplateChild("TextBlockControl") as FrameworkElement;
base.OnApplyTemplate();
}

Make dependency object properties bindable as a static resource?

How to make an array of dependency object properties bindable for later binding as a static resource?
The code I have now, it seems that my DependencyObject bypasses the dependency property system...
I have the following class:
public class ValueMarker : DependencyObject
{
public static readonly DependencyProperty BrushProperty = DependencyProperty.Register("Brush", typeof(Brush), typeof(ValueMarker), new FrameworkPropertyMetadata(Brushes.Aqua));
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(double), typeof(ValueMarker), new FrameworkPropertyMetadata(0d));
public static readonly DependencyProperty OffsetProperty = DependencyProperty.Register("Offset", typeof(double), typeof(ValueMarker), new FrameworkPropertyMetadata(0d));
public Brush Brush
{
get { return (Brush)GetValue(BrushProperty); }
set { SetValue(BrushProperty, value); }
}
public double Offset
{
get { return (double)GetValue(OffsetProperty); }
set { SetValue(OffsetProperty, value); }
}
public double Value
{
get { return (double)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
}
In the XAML, I create a resource array of these with some bindings like so:
<x:Array Type="my:ValueMarker" x:Key="plainMarks">
<my:ValueMarker Brush="Red" Offset="-5" Value="{Binding Path=...}" />
<my:ValueMarker Brush="Orange" Offset="-5" Value="{Binding Path=...}"/>
<my:ValueMarker Brush="Orange" Offset="-5" Value="{Binding Path=...}"/>
<my:ValueMarker Brush="Red" Offset="-5" Value="{Binding Path=...}" />
</x:Array>
While debugging the bindings, I've noticed that should I remove the setter for the DP, the XAML would display an error saying the property is missing. It was my understanding that XAML uses DP system to assign value thus enabling binding. In this case, if the XAML expect a 'normal' property, binding is impossible. Anyone can enlighten me on how can I make it work?
The reason you cannot bind your ValueMarkers here is because:
1.They are not in the VisualTree of your window/usercontrol.
2.They are not object of Type that can inherit DataContext even if they are not part of Visual Tree.
So in order to make your ValueMarkers bind to the properties in the View DataContext, first of all you will have to derive them from Freezable class like below:
public class ValueMarker : Freezable
{
//All your Dependency Properties comes here//
protected override Freezable CreateInstanceCore()
{
return new ValueMarker();
}
}
After doing this you can simply bind your object like below:
<my:ValueMarker x:Key="vm1" Brush="Orange" Offset="-5" Value="{Binding Path=Text1}"/>
Here Text1 is property in Windows/usercontrols DataContext
Then you can use this resource as:
<TextBox Text="{Binding Value, Source={StaticResource vm1}, StringFormat=F2}"/>
Similarly you can create resource for other ValueMarkers to use them in binding.
You will not be able to bind by creating the x:Array as simply x:Array not lies in visualtree and does not inherit DataContext hence its elements also have no access to it.
If you still want to use the collection whose element should support binding, then you will need to create your own collection class that should inherit Freezable and exposes DependancyProperty to capture the DataContext and set it on child elements also.

Categories