This is a migrated thread and some comments may be shown as answers.

Why does IsPinned need TwoWay binding?

2 Answers 110 Views
Docking
This is a migrated thread and some comments may be shown as answers.
Rami
Top achievements
Rank 1
Veteran
Rami asked on 04 Nov 2020, 07:36 AM

Hello,

 

it seems that having a RadPane with a binding for its IsPinned property needs to bound with Mode=TwoWay for it to work. Why is this? The problem comes more apparent when I'm using (in the real application) binding to a ViewModel that gets converted through a (Multi)ValueConverter. If I have to have the binding mode be TwoWay I have to implement the ConvertBack method of IValueConverter and have it return something like null, even though I only want the model converted one way. I absolutely do not want the pinned/unpinned status of the RadPane having any influence on my model.

 

Also, it seems the ConvertBack is only called once at the start of the program or when the actual pin/unpin icon is pressed. And this is very bad when we have the TextBox binding. If I write a string longer than 5 characters into it, the pane opens. If I then unpin the pane, the TextBox is cleared because the converter returns null!

 

Below is a repro of the problem, standard WPF .NET 4.7.2 project with only the Telerik nugets added. Clicking the checkbox Pane 1 does nothing. The checkbox Pane 2 pins/unpins Pane 2 because it is bound with Mode=TwoWay. The same can be seen with the textbox. When typing a string more than 5 characters in length, the last pane opens if the binding mode is TwoWay.

 

My MainWindow.xaml

01.<Window x:Class="TelerikDockingIsPinned.MainWindow"
06.        xmlns:local="clr-namespace:TelerikDockingIsPinned"
07.        xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
08.        mc:Ignorable="d"
09.        Title="MainWindow" Height="450" Width="800">
10. 
11.    <Window.Resources>
12.        <local:TextLengthConverter x:Key="TextLenConverter" />
13.    </Window.Resources>
14. 
15.    <Grid>
16.        <Grid.RowDefinitions>
17.            <RowDefinition Height="Auto"/>
18.            <RowDefinition Height="*"/>
19.        </Grid.RowDefinitions>
20. 
21.        <StackPanel Orientation="Horizontal">
22.            <CheckBox x:Name="Pane1Pinned" Content="Pane 1"/>
23.            <CheckBox x:Name="Pane2Pinned" Content="Pane 2"/>
24.            <TextBox x:Name="Pane3Pinned" MinWidth="100"/>
25.        </StackPanel>
26. 
27.        <telerik:RadDocking Grid.Row="1">
28.            <telerik:RadSplitContainer>
29.                <telerik:RadPaneGroup>
30.                    <telerik:RadPane Header="Pane 1" IsPinned="{Binding ElementName=Pane1Pinned, Path=IsChecked}"/>
31.                    <telerik:RadPane Header="Pane 2" IsPinned="{Binding ElementName=Pane2Pinned, Path=IsChecked, Mode=TwoWay}"/>
32.                    <telerik:RadPane Header="Pane 3" IsPinned="{Binding ElementName=Pane3Pinned, Path=Text, Converter={StaticResource TextLenConverter}, Mode=TwoWay}"/>
33.                </telerik:RadPaneGroup>
34.            </telerik:RadSplitContainer>
35.        </telerik:RadDocking>
36.    </Grid>
37.</Window>

 

and the converter:

01.using System;
02.using System.Globalization;
03.using System.Windows.Data;
04. 
05.namespace TelerikDockingIsPinned {
06.    class TextLengthConverter : IValueConverter {
07.        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
08.            return (value is string) && ((string)value).Length > 5;
09.        }
10. 
11.        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
12.            Console.WriteLine("ConvertBack called");
13. 
14.            return null;
15.        }
16.    }
17.}

2 Answers, 1 is accepted

Sort by
0
Accepted
Martin Ivanov
Telerik team
answered on 06 Nov 2020, 11:53 AM

Hello Rami,

This TwoWay binding mode is required because the IsPinned property is set on few places in code by the RadDocking's internal code. Setting a direct value in code has a higher priority than using a OneWay binding. On the other hand, the direct value priority is lower than the TwoWay binding. 

If you do not want to use TwoWay binding, you can try an approach with an attached property. Here is an example in code:

public static class DockingPaneUtilities
{
	public static bool GetIsPinned(DependencyObject obj)
	{
		return (bool)obj.GetValue(IsPinnedProperty);
	}

	public static void SetIsPinned(DependencyObject obj, bool value)
	{
		obj.SetValue(IsPinnedProperty, value);
	}

	public static readonly DependencyProperty IsPinnedProperty =
		DependencyProperty.RegisterAttached(
			"IsPinned", 
			typeof(bool), 
			typeof(DockingPaneUtilities),
			new PropertyMetadata(false, OnIsPinnedChanged));

	private static void OnIsPinnedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
	{
		var pane = (RadPane)d;
		pane.IsPinned = (bool)e.NewValue;
	}
}
 
<telerik:RadPane Header="Pane 3" local:DockingPaneUtilities.IsPinned="{Binding ElementName=Pane3Pinned, Path=Text, Converter={StaticResource TextLenConverter}, Mode=OneWay}"/>

Regards,
Martin Ivanov
Progress Telerik

Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.

0
Rami
Top achievements
Rank 1
Veteran
answered on 10 Nov 2020, 11:47 AM

Hello Martin,

 

the attached property seems like a good workaround. Thank you for your help.

Tags
Docking
Asked by
Rami
Top achievements
Rank 1
Veteran
Answers by
Martin Ivanov
Telerik team
Rami
Top achievements
Rank 1
Veteran
Share this question
or