WPF Attached Property triggering twice - wpf

I am trying to learn dependency properties and attached properties, so please forgive me if you find no use in what I am trying to do.
I have a usual MVVM approach with a Window whose datacontext is set to a VM, and View which is a datatemplate containing a usercontrol targetting such VM.
I am trying to make the window container as dumb as possible, as such i'm trying to define some parameters that usually reside in the window XAML (e.g. the height) via the usercontrol using Attached Properties.
For that purpose I created the following class where I define the attached property:
public static class WpfExtensions
{
public static readonly DependencyProperty ContainerHeightProperty = DependencyProperty.RegisterAttached(
"ContainerHeight",
typeof(double),
typeof(WpfExtensions),
new FrameworkPropertyMetadata(300.0, FrameworkPropertyMetadataOptions.AffectsParentArrange | FrameworkPropertyMetadataOptions.AffectsParentMeasure | FrameworkPropertyMetadataOptions.AffectsRender, ContainerHeight)
);
public static void SetContainerHeight(UIElement element, double value)
{
element.SetValue(ContainerHeightProperty, value);
}
public static double GetContainerHeight((UIElement element)
{
return (double)element.GetValue(ContainerHeightProperty);
}
private static void ContainerHeight(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is UserControl)
{
UserControl l_Control = (UserControl)d;
Binding l_Binding = new Binding();
l_Binding.RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(Window), 1);
l_Binding.Path = new PropertyPath("Height");
l_Binding.Mode = BindingMode.OneWayToSource;
BindingOperations.SetBinding(d, e.Property, l_Binding);
}
}
}
as you can see, to achieve the control of the container window height I am creating a binding in code from the attached property up to the container window.
However the ContainerHeight change get fired twice. The first time I get a change from 300 (the default) to 1024(what is defined in XAML). Then I immediately receive another one from 1024 back to 300 and I am not understanding why.
The window code is very simple:
<Window x:Class="WpfApplication.DialogWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:lcl="clr-namespace:WpfApplication"
Title="DialogWindow">
<Window.Resources>
<DataTemplate DataType="{x:Type lcl:Dialog_VM}">
<lcl:Dialog_VM_View />
</DataTemplate>
</Window.Resources>
<ContentPresenter Content="{Binding }" />
</Window>
and finally the simple ViewModel
<UserControl x:Class="WpfApplication.Dialog_VM_View"
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:lcl="clr-namespace:WpfApplication"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
lcl:WpfExtensions.ContainerHeight="1024">
<StackPanel>
<TextBlock Text="This is a test" />
</StackPanel>
</UserControl>

You should bind the Height property of the parent window to the attached property and not the other way around, shouldn't you?
This sets (binds) the Height of the parent window to 1024 which is the value of the dependency property in the UserControl:
private static void ContainerHeight(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is UserControl)
{
UserControl l_Control = (UserControl)d;
if (!l_Control.IsLoaded)
{
l_Control.Loaded += L_Control_Loaded;
}
else
{
Bind(l_Control);
}
}
}
private static void L_Control_Loaded(object sender, RoutedEventArgs e)
{
UserControl l_Control = (UserControl)sender;
Bind(l_Control);
}
private static void Bind(UserControl l_Control)
{
Window window = Window.GetWindow(l_Control);
Binding l_Binding = new Binding();
l_Binding.Path = new PropertyPath(WpfExtensions.ContainerHeightProperty);
l_Binding.Source = l_Control;
BindingOperations.SetBinding(window, Window.HeightProperty, l_Binding);
}

Related

User control's Dependency Property doesn't get bound in Silverlight

I have created a user control like numeric updown as follows
<StackPanel Orientation="Horizontal" VerticalAlignment="Top" >
<TextBox x:Name="InputTextBox" Grid.Row="0" Grid.Column="0" Grid.RowSpan="1"
Style="{StaticResource NumericUpDownTextBoxStyle}"
KeyDown="InputTextBox_KeyDown"
KeyUp="InputTextBox_KeyUp"
GotFocus="InputTextBox_GotFocus"
LostFocus="InputTextBox_LostFocus"
MouseWheel="InputTextBox_MouseWheel"
MouseEnter="InputTextBox_MouseEnter"
LayoutUpdated="InputTextBox_LayoutUpdated"
Text="{Binding Path=ControlValue, Mode=TwoWay,ValidatesOnDataErrors=True,ValidatesOnExceptions=True,NotifyOnValidationError=True}"/>
</StackPanel>
I have bind a ViewModel to this control where I Set ControlValue property to TextBox property of the user control template textbox.
Everthing works fine at a control level. I have exposed from usercontrol.
public static readonly DependencyProperty MaximumValueProperty;
public static readonly DependencyProperty MinimumValueProperty;
public static readonly DependencyProperty StepValueProperty;
public static readonly DependencyProperty TextValueProperty;
My Properties are
public double Maximum
{
get
{
return (double)GetValue(MaximumValueProperty);
}
set
{
SetValue(MaximumValueProperty, value);
this.ViewModel.Maximum = this.Maximum;
}
}
public double Minimum
{
get
{
return (double)GetValue(MinimumValueProperty);
}
set
{
SetValue(MinimumValueProperty, value);
this.ViewModel.Minimum = this.Minimum;
}
}
public double Step
{
get
{
return (double)GetValue(StepValueProperty);
}
set
{
SetValue(StepValueProperty, value);
this.ViewModel.Step = this.Step;
}
}
public double TextValue
{
get
{
return (double)GetValue(TextValueProperty);
}
set
{
SetValue(TextValueProperty, value);
this.ViewModel.ControlValue = Convert.ToString(value);
}
}
Initialization of the property.
static NumericUpDown()
{
MaximumValueProperty = DependencyProperty.Register("Maximum", typeof(double), typeof(NumericUpDown), new PropertyMetadata(null));
MinimumValueProperty = DependencyProperty.Register("Minimum", typeof(double), typeof(NumericUpDown), new PropertyMetadata(null));
StepValueProperty = DependencyProperty.Register("Step", typeof(double), typeof(NumericUpDown), new PropertyMetadata(null));
TextValueProperty = DependencyProperty.Register("TextValue", typeof(double), typeof(NumericUpDown), new PropertyMetadata(null));
}
My Usercontrol implementation in the MainPage.xaml page as follows
<local:NumericUpDown Maximum="28" Minimum="-28" Step="0.25" TextValue="{Binding ElementName=FranePrice, Path=DataContext.FranePrice}"></local:NumericUpDown>
Where I have another ViewModel which i bind to the XAML page and there is a Property in the ViewModel which i bind to the TextValue property of the Usercontrol.
FramePrice is property in the View model that i bind to the TextValue property of the user control
and Main page XAML is
<UserControl x:Class="DatePicker.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:DatePicker"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk">
<Grid x:Name="LayoutRoot" Background="White">
<StackPanel Orientation="Vertical">
<local:NumericUpDown Maximum="28" Minimum="-28" Step="0.25" TextValue="{Binding ElementName=FranePrice, Path=DataContext.FranePrice}"></local:NumericUpDown>
<Button Content="Show Date" Height="23" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click"/>
</StackPanel>
</Grid>
This View model of the page where i used user control. On click event i showing TextValue to user.
public class MainPageViewModel : EntityViewModel
{
public MainPageViewModel()
{
}
private double framePrice;
public Double FramePrice
{
get
{
return framePrice;
}
set
{
framePrice = value;
PropertyChangedHandler("FramePrice");
}
}
}
When I change the TextValue in the User control it doesnot change in the FramePrice property of the page viewmodel.
Is anything wrong in the code.???
As per Luke Woodward's post I have updated code as follows
public static readonly DependencyProperty MaximumValueProperty;
public static readonly DependencyProperty MinimumValueProperty;
public static readonly DependencyProperty StepValueProperty;
public static readonly DependencyProperty TextValueProperty;
public static double Max;
public static double Min;
public static double Stp;
public static double Val;
public double Maximum
{
get
{
return (double)GetValue(MaximumValueProperty);
}
set
{
SetValue(MaximumValueProperty, value);
}
}
public double Minimum
{
get
{
return (double)GetValue(MinimumValueProperty);
}
set
{
SetValue(MinimumValueProperty, value);
}
}
public double Step
{
get
{
return (double)GetValue(StepValueProperty);
}
set
{
SetValue(StepValueProperty, value);
}
}
public double TextValue
{
get
{
return (double)GetValue(TextValueProperty);
}
set
{
SetValue(TextValueProperty, value);
}
}
static NumericUpDown()
{
MaximumValueProperty = DependencyProperty.Register("Maximum", typeof(double), typeof(NumericUpDown), new PropertyMetadata(new PropertyChangedCallback(onMaximumValueChanged)));
MinimumValueProperty = DependencyProperty.Register("Minimum", typeof(double), typeof(NumericUpDown), new PropertyMetadata(new PropertyChangedCallback(onMinimumValueChanged)));
StepValueProperty = DependencyProperty.Register("Step", typeof(double), typeof(NumericUpDown), new PropertyMetadata(new PropertyChangedCallback(onStepValueChanged)));
TextValueProperty = DependencyProperty.Register("TextValue", typeof(double), typeof(NumericUpDown), new PropertyMetadata(new PropertyChangedCallback(onTextValueChanged)));
}
private static void onStepValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Stp = (double)e.NewValue;
}
private static void onMinimumValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Min = (double)e.NewValue;
}
private static void onMaximumValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Max = (double)e.NewValue;
}
private static void onTextValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Val = (double)e.NewValue;
}
Then i accessed Max, Min , Stp and Val property in user control's view model to perform my logic.
and XAML code is follows
<local:NumericUpDown x:Name="ctlUpDown" Maximum="28" Minimum="-28" Step="0.25" TextValue="{Binding Path=FramePrice}"></local:NumericUpDown>
and XAML of user control
<StackPanel Margin="5" Orientation="Horizontal" VerticalAlignment="Center">
<TextBox x:Name="InputTextBox" Grid.Row="0" Grid.Column="0" Grid.RowSpan="1"
Height="23" VerticalAlignment="Top"
Width="50" TextAlignment="Center"
KeyDown="InputTextBox_KeyDown"
KeyUp="InputTextBox_KeyUp"
GotFocus="InputTextBox_GotFocus"
LostFocus="InputTextBox_LostFocus"
MouseWheel="InputTextBox_MouseWheel"
MouseEnter="InputTextBox_MouseEnter"
Text="{Binding Path=TextValue, ElementName=ctlUpDown, Mode=TwoWay,ValidatesOnDataErrors=True,ValidatesOnExceptions=True,NotifyOnValidationError=True}"
/>
</StackPanel>
The first thing I noticed wrong about your code was the properties Maximum, Minimum, Step and TextValue. Here's the TextValue property:
public double TextValue
{
get
{
return (double)GetValue(TextValueProperty);
}
set
{
SetValue(TextValueProperty, value);
this.ViewModel.ControlValue = Convert.ToString(value);
}
}
Properties that are backed by a dependency property, such as the four I mentioned above, should ALWAYS look like the following:
public double TextValue
{
get { return (double)GetValue(TextValueProperty); }
set { SetValue(TextValueProperty, value); }
}
In other words, the getter should contain nothing more than a call to GetValue, and the setter should contain nothing more than a call to SetValue.
The reason for this is that when Silverlight changes the value of the TextValue dependency property, it won't do it by using the property above. The values of dependency properties are stored within the Silverlight dependency system, and when Silverlight wants to change the value of one of them, it goes directly to this dependency system. It doesn't call your code at all. Properties like that above are provided only for your convenience, giving you an easy way to access and change the value stored in the dependency property. They will never be called by anything other than your own code.
Generally, if you want a method to be called whenever a dependency property value changes, you need to pass a PropertyChangedCallback in the PropertyMetadata when registering the dependency property. However, I suspect that in your case you won't need to do that.
It seems to me that you have three properties:
the FramePrice property in your view-model class,
the TextValue dependency property of your NumericUpDown user control,
the Text dependency property of the TextBox within your NumericUpDown user control's XAML.
My impression is that you want the FramePrice property in your view-model to always have the same value as the Text property of the TextBox. To do that, you need to bind the FramePrice property to the NumericUpDown's TextValue property, and then bind that to the Text property of the TextBox.
To bind the first two of these properties together, there are a couple of things to change. Firstly, the TextValue property in your <local:NumericUpDown> element should look like
TextValue="{Binding Path=FramePrice}"
The binding {Binding ElementName=FramePrice, Path=DataContext.FramePrice} won't work, because there's no element in your XAML with the attribute x:Name="FramePrice". The value of an ElementName property in a {Binding ...} must match the x:Name of an object in the XAML.
You also need to set up the DataContext for your main page. If your main page view-model object has a zero-argument constructor, one way of doing this is to follow this answer.
To bind the second two properties together, I would:
add an x:Name attribute to the <UserControl> element of your NumericUpDown control (x:Name="ctlUpDown", say),
replace the Text property of the TextBox within your NumericUpDown control with the following:
Text="{Binding Path=TextValue, ElementName=ctlUpDown, Mode=TwoWay, ValidatesOnDataErrors=True, ValidatesOnExceptions=True, NotifyOnValidationError=True}"/>
Once you've done that, you can then remove all of the lines this.ViewModel.SomeProperty = ... from your code-behind class. They're not necessary, and as I've already explained they won't be run when you wanted them to.
Finally, is there a reason you're not using the Silverlight Toolkit's NumericUpDown control?
EDIT 2: Against my better judgement I took a look at one of the two Silverlight projects you uploaded (I ignored the one with _2 in it). It bears very little resemblance to your question.
I can only assume you want the two textboxes (one of which is in a user control) to always have the same value. I was able to do this after making the following changes:
MainPageViewModel.cs: add ClearErrorFromProperty("DPropertyBind"); to the property setter. (Otherwise the validation error never gets cleared.)
MyUserControlWVM.xaml: removed reference to LostFocus event handler, added binding on Text property and added add x:Name attribute to the <UserControl> element. In other words, it now looks like the following:
<UserControl x:Class="DependencyPropertyBinding.MyUserControlWVM"
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"
x:Name="ctlWVM"
d:DesignHeight="300" d:DesignWidth="205">
<StackPanel Orientation="Horizontal" Width="204" Height="32">
<TextBox x:Name="textbox" Height="30" Width="200" Text="{Binding Path=DProperty, ElementName=ctlWVM, Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnDataErrors=True, ValidatesOnExceptions=True}" />
</StackPanel>
</UserControl>
MyUserControlWVM.xaml.cs: renamed dependency property DependencyPropertyValue to DPropertyProperty (the naming convention is that the static readonly field has the name of the property (in this case DProperty) with Property appended). I also removed the TextBox_LostFocus event handler.
If the code above is accurate you have spelt FramePrice as FranePrice in the binding
The output window should have shown this as a binding error when the page loaded.
it is currently
Binding ElementName=FranePrice, Path=DataContext.FranePrice
should be:
Binding ElementName=FramePrice, Path=DataContext.FramePrice
"With great binding capabilities comes great responsibility" :)

Behaviour of ItemsControl

I have a screen with several UserControls, but only one of them remains active. The other UserControls aren't shown, but the user can switch the active flag of any of those who are not active. One of the UserControl contains an ItemsControl.
I need to know all the controls in the view, including those generated by an ItemsControl, after loading the first UserControl that is active in the screen, when view is finally initialized.
For ItemsControl, wpf didn't instance any item until it was painted on the screen that contains the UserControl (so I've tried, until the Load event is launched), so that I can't found the controls contained by the view because it didn't exist.
Is there any way to change this behavior?
I try to change the value of property VirtualizingStackPanel.IsVirtualizing to false, to avoid the previous behaviour, with no success. To illustrate this, I write this view example:
<Window x:Class="ContenidoEnTabs.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">
<StackPanel x:Name="spContainer" Orientation="Vertical" VirtualizingStackPanel.IsVirtualizing="False">
<Button Content="Push" Click="Button_Click" />
</StackPanel>
</Window>
This view creates a second control not visible until the user press the button:
public partial class MainWindow : Window
{
private NotPaintedOnInitUserControl controlExtra;
public MainWindow()
{
InitializeComponent();
controlExtra = new NotPaintedOnInitUserControl();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
spContainer.Children.Add(controlExtra);
}
}
The control not visible initially is as follow:
<UserControl x:Class="ContenidoEnTabs.NotPaintedOnInitUserControl"
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">
<ItemsControl ItemsSource="{Binding MyCollection}" x:Name="itemsControlTarget"
VirtualizingStackPanel.IsVirtualizing="False">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox x:Name="aTextBox" Width="80" Initialized="ATextBox_Initialized" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</UserControl>
and in CodeBehind I detect when the Items were created
public partial class NotPaintedOnInitUserControl : UserControl
{
public NotPaintedOnInitUserControl()
{
InitializeComponent();
DataContext = new SimpleListDataContext();
}
private void ATextBox_Initialized(object sender, EventArgs e)
{
}
}
And the DataContext used:
public class SimpleListDataContext
{
private List<string> _myCollection;
public List<string> MyCollection
{
get { return _myCollection ?? (_myCollection = new List<string> { "one", "two" }); }
set { _myCollection = value; }
}
}
Any ideas?
Thanks in advance.
If you want WPF to generate the tree for a control that isn't part of the view, you can "hydrate" and layout the control by forcing the layout to run. Something like this should work:
public partial class MainWindow : Window
{
private NotPaintedOnInitUserControl controlExtra;
public MainWindow()
{
InitializeComponent();
controlExtra = new NotPaintedOnInitUserControl();
// Force the control to render, even though it's not on the screen yet.
var size = new Size(this.Width, this.Height);
var rect = new Rect(new Point(0,0), size);
controlExtra.Measure(size);
controlExtra.Arrange(rect);
controlExtra.InvalidateVisual();
controlExtra.UpdateLayout();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
spContainer.Children.Add(controlExtra);
}
}
Not sure if this is what you're asking. If not, please clarify paragraph 2.
Have a look at LogicalTreeHelper.GetChildren(myUiElement)
This looks at the logical tree rather than the visual tree so it examines the structure without needing to have loaded the control to get the visual structure
In the below control to find is the name of the contorl i.e. myDatagrid
You could also adapt this to just get all the children of a particular control i.e.
FindChildInVisualTree(this, "mydatagrid"); // assumming this a UIElement (i.e. your in the code behind)
find the control using the below then using LogicalTreeHelper get all it's children.
public static UIElement FindChildInVisualTree(UIElement view, string controlToFind)
{
UIElement control = null;
try
{
if (view != null)
{
if ((view as FrameworkElement).Name.ToUpper() == controlToFind.ToUpper())
{
control = view;
}
else
{
DependencyObject depObj = view as DependencyObject;
if (depObj != null)
{
foreach (var item in LogicalTreeHelper.GetChildren(depObj))
{
control = FindChildInVisualTree(item as UIElement, controlToFind);
if (control != null)
{
break;
}
}
}
}
}
}
catch (Exception ex)
{
throw new ApplicationException("Error finding child control: " + controlToFind, ex);
}
return control;
}

How do i bind string (in xaml format) to xaml property of RichTextBox in silverlight?

I have the following xaml,
<RichTextBox Name="RichTextBoxPostContent" Margin="0" Padding="8,8,8,0" IsReadOnly="True" Foreground="{x:Null}" Xaml="{Binding Path=PostContent}"/>
and PostContent (a string) has xaml stored as string and im not sure how to bind it to RichTextBox's Xaml property, the following is the value of PostContent,
<Section xml:space="preserve" HasTrailingParagraphBreakOnPaste="False" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"><Paragraph FontSize="11" FontFamily="Portable User Interface" Foreground="#FF000000" FontWeight="Normal" FontStyle="Normal" FontStretch="Normal" TextAlignment="Left"><Run Text="aaa" /></Paragraph></Section>
You can create your own attached property if you want to use data binding.
The code sample below adds an attached property to the RichTextBox named XamlSource, which you can use to bind against.
public static class RichTextBoxBinder
{
#region RichTextBox attached properties
public static readonly DependencyProperty XamlSourceProperty =
DependencyProperty.RegisterAttached(
"XamlSource",
typeof(string),
typeof(RichTextBox),
new PropertyMetadata(OnXamlSourcePropertyChanged));
private static void OnXamlSourcePropertyChanged(
DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
var rtb = d as RichTextBox;
if (rtb == null) throw new ArgumentException(
"Expected a dependency object of type RichTextBox.", "d");
string xaml = null;
if (e.NewValue != null)
{
xaml = e.NewValue as string;
if (xaml == null) throw new ArgumentException("Expected a value of type string.", "e.NewValue");
}
// Set the xaml and reset selection
rtb.Xaml = xaml ?? string.Empty;
rtb.Selection.Select(rtb.ContentStart, rtb.ContentStart);
}
#endregion
public static void SetXamlSource(this RichTextBox rtb, string xaml)
{
rtb.SetValue(XamlSourceProperty, xaml);
}
public static string GetXamlSource(this RichTextBox rtb)
{
return (string) rtb.GetValue(XamlSourceProperty);
}
}
If the property you want to bind against looks like this:
public string MyRichTextXamlProperty
{
get
{
return
string.Concat(
#"<Section xml:space=""preserve"" HasTrailingParagraphBreakOnPaste=""False""",
#" xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"">",
#"<Paragraph FontSize=""11"" FontFamily=""Portable User Interface""",
#" Foreground=""#FF000000"" FontWeight=""Normal"" FontStyle=""Normal""",
#" FontStretch=""Normal"" TextAlignment=""Left""><Run Text=""aaa"" />",
#"</Paragraph></Section>"
);
// Hints: (Thanks Christoph)
// 1) Pay special attention that you include the appropriate XML namespaces
// e.g. 2nd parameter in string.Concat above.
// 2) When you have to use resources, they have to be DynamicResource and
// not StaticResource. This is because your resources are only available
// at runtime.
}
}
Then your xaml looks similar to this:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MyNamespace"
x:Class="MyClass" >
<Grid>
<RichTextBox local:RichTextBoxBinder.XamlSource="{Binding MyRichTextXamlProperty}" />
</Grid>
</UserControl>
Xaml isn't a dependency property in Silverlight, so you can't bind to it. You'll have to write code that subscribes to INotifyPropertyChanged and does richTextBox.Xaml = obj.PostContent whenever it changes.

User control with richTextBox, bindable richTextBox

I try make user control with richTextBox because I need bindable richTextbox.
I found some solution here: Richtextbox wpf binding.
I would like to use solution of Arcturus. Create user control with richTextBox control and use dependency property.
In XAML I have only richTextBox control:
<UserControl x:Class="WpfApplication2.BindableRichTextBoxControl"
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>
<RichTextBox Name="RichTextBox" Grid.Row="0"/>
</Grid>
</UserControl>
In CodeBehind:
public partial class BindableRichTextBoxControl : UserControl
{
public static readonly DependencyProperty DocumentProperty =
DependencyProperty.Register("Document", typeof(FlowDocument), typeof(BindableRichTextBoxControl),
new PropertyMetadata(OnDocumentChanged));
public FlowDocument Document
{
get { return (FlowDocument)GetValue(DocumentProperty); }
set { SetValue(DocumentProperty, value); }
}
private static void OnDocumentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = (BindableRichTextBoxControl)d;
if (e.NewValue == null)
control.RichTextBox.Document=new FlowDocument();
//?
control.RichTextBox.Document = document;
}
public BindableRichTextBoxControl()
{
InitializeComponent();
}
}
I am little confuse with last line in OnDocumentChanged method.
control.RichTextBox.Document = document;
I can’t identify what is varibale document.
I think he means this:
private static void OnDocumentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
RichTextBoxControl control = (RichTextBoxControl) d;
if (e.NewValue == null)
control.RTB.Document = new FlowDocument(); //Document is not amused by null :)
else
control.RTB.Document = e.NewValue;
}
but I recommend you leave a comment on his original answer.

Silverlight ComboBox Attached Behavior

I am trying to create an attached behavior that can be applied to a Silverlight ComboBox.
My behavior is this:
using System.Windows.Controls;
using System.Windows;
using System.Windows.Controls.Primitives;
namespace AttachedBehaviours
{
public class ConfirmChangeBehaviour
{
public static bool GetConfirmChange(Selector cmb)
{
return (bool)cmb.GetValue(ConfirmChangeProperty);
}
public static void SetConfirmChange(Selector cmb, bool value)
{
cmb.SetValue(ConfirmChangeProperty, value);
}
public static readonly DependencyProperty ConfirmChangeProperty =
DependencyProperty.RegisterAttached("ConfirmChange", typeof(bool), typeof(Selector), new PropertyMetadata(true, ConfirmChangeChanged));
public static void ConfirmChangeChanged(DependencyObject d, DependencyPropertyChangedEventArgs args)
{
Selector instance = d as Selector;
if (args.NewValue is bool == false)
return;
if ((bool)args.NewValue)
instance.SelectionChanged += OnSelectorSelectionChanged;
else
instance.SelectionChanged -= OnSelectorSelectionChanged;
}
static void OnSelectorSelectionChanged(object sender, RoutedEventArgs e)
{
Selector item = e.OriginalSource as Selector;
MessageBox.Show("Unsaved changes. Are you sure you want to change teams?");
}
}
}
This is used in XAML as this:
<UserControl x:Class="AttachedBehaviours.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:this="clr-namespace:AttachedBehaviours"
mc:Ignorable="d">
<Grid x:Name="LayoutRoot">
<StackPanel>
<ComboBox ItemsSource="{Binding Teams}"
this:ConfirmChangeBehaviour.ConfirmChange="true" >
</ComboBox>
</StackPanel>
</Grid>
</UserControl>
I am getting an error:
Unknown attribute ConfirmChangeBehaviour.ConfirmChange on element ComboBox. [Line: 13 Position: 65]
Intellisense is picking up the behavior, why is this failing at runtime?
Thanks,
Mark
EDIT: Register() changed to RegisterAttached(). Same error appears.
You've misregistered your attached property
public static readonly DependencyProperty ConfirmChangeProperty =
DependencyProperty.RegisterAttached("ConfirmChange", typeof(bool), typeof(Selector), new PropertyMetadata(true, ConfirmChangeChanged));
Should be
public static readonly DependencyProperty ConfirmChangeProperty =
DependencyProperty.RegisterAttached("ConfirmChange", typeof(bool), typeof(ConfirmChangeBehaviour), new PropertyMetadata(true, ConfirmChangeChanged));
May I advise you to move over to using the Blend Interactivity Behaviours. Writing XAML as opposed to using a tool never makes Designers happy.
You need to change this:
DependencyProperty.Register("ConfirmChange"...
to this:
DependencyProperty.RegisterAttached("ConfirmChange"...
Attached properties (including attached behaviours) must be registered using RegisterAttached rather than plain old Register.

Resources