vloerderbe
vloerderbe

Reputation: 15

how to make a dependency property of type bool a two way binding

Can anyone help me with this problem , because i read a blog how to do this on Walkthrough: Two-way binding inside a XAML User Control but i don't now how to do this with a bool value

    public bool IsSelected
    {
        get { return (bool)GetValue(IsSelectedProperty); }
        set { SetValueIsSelected(IsSelectedProperty, value); }
    }

    private void SetValueIsSelected(DependencyProperty property, object value,
        [System.Runtime.CompilerServices.CallerMemberName] bool s = null)
    {
        SetValue(property, value);
        if (PropertyChanged != null)
        {
            string sender = s.ToString();
            PropertyChanged(this, new PropertyChangedEventArgs(sender));
        }
    }
    // Using a DependencyProperty as the backing store for IsSelected.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty IsSelectedProperty =
        DependencyProperty.Register("IsSelected", typeof(bool), typeof(CustomPolygon), new PropertyMetadata(0));

So this was wrong accordingly @Clemens to understand it more here i some more information on my application

In my MainWindow i am using two ComboBoxes to fill my data with binding to a public ObservableCollection DataPlannen

My code behind MainWindow:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private ObservableCollection<Plan> dataPlannen;
    public ObservableCollection<Plan> DataPlannen
    {
        get { return dataPlannen; }
        set
        {
            if (value != dataPlannen)
            {
                dataPlannen = value;
            }
        }
    }

    //non relevant code deleted


    //get database data for ComboBoxes
    private void btnGetPlanData_Click(object sender, RoutedEventArgs e)
    {
        try
        {
            this.Cursor = Cursors.Wait;
            DataPlannen = new PlanCanvasModel().PlanHotspotsHardwares;             
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.ToString();
        }
        finally
        {
            this.Cursor = Cursors.Arrow;
        }
    }

    private void cmbHotspot_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
       if (cmbHotspot.SelectedIndex != -1)
       {
         foreach (Hotspot hotspot in cmbHotspot.ItemsSource)
         {
            if (hotspot == (Hotspot)cmbHotspot.SelectedItem)
            {
                 hotspot.IsSelected = true;

             else
             {
                 hotspot.IsSelected = false;
              }
          }
    }
}

My MainWindow XAML:

    <Grid Background="LightGray">
    <DockPanel Name="TestCanvas" LastChildFill="True">
        <Grid x:Name="Sidebar" DockPanel.Dock="Right" Width="200">
            <StackPanel Margin="0,10,10,0">
                <ScrollViewer Height="112" VerticalScrollBarVisibility="Auto">
                    <StackPanel>
                        <StackPanel Orientation="Horizontal" Margin="0,0,0,5">
                            <Button x:Name="btnGetPlanData" Width="30" Height="30" HorizontalAlignment="Left" Margin="5,0" Click="btnGetPlanData_Click">
                                <Image Source="Images/database38.png" Stretch="Uniform"></Image>
                                <Button.ToolTip>Laad plannen in</Button.ToolTip>
                            </Button>

                        </StackPanel>
                        <Grid>
                            <ComboBox x:Name="cmbPlannen" Width="180"
                                      ItemsSource="{Binding ElementName=myWindow,Path=DataPlannen}" 
                                      DisplayMemberPath="{Binding Plan_naam}"
                                      SelectedValuePath="{Binding Plan_Id}"
                                      SelectionChanged="cmbPlannen_SelectionChanged" IsEditable="True">
                                <ComboBox.ToolTip>
                                    <ToolTip>Zoek op text of selecteer</ToolTip>
                                </ComboBox.ToolTip>
                            </ComboBox>

                        </Grid>
                    </StackPanel>
                </ScrollViewer>
                <Grid>
                    <ComboBox Margin="5" SnapsToDevicePixels="True" ItemsSource="{Binding ElementName=cmbPlannen,Path=SelectedItem.Hotspots,Mode=TwoWay}"
                              x:Name="cmbHotspot" SelectedIndex="0"
                              DisplayMemberPath="{Binding Hotspot_naam}"
                              SelectedValuePath="{Binding Hotspot_Id}"
                              SelectedItem="{Binding SelectedItem}"
                              SelectionChanged="cmbHotspot_SelectionChanged"  IsEditable="True">
                        <ComboBox.ItemContainerStyle>
                            <Style>
                                <Setter Property="Control.Padding" Value="0"></Setter>
                                <Style.Triggers>
                                    <Trigger Property="ComboBoxItem.IsSelected" Value="True">
                                        <Setter Property="ComboBoxItem.Background" Value="LightGray" />
                                    </Trigger>
                                    <Trigger Property="ComboBoxItem.IsHighlighted" Value="True">
                                        <Setter Property="ComboBoxItem.Background" Value="White" />
                                    </Trigger>
                                </Style.Triggers>
                            </Style>
                        </ComboBox.ItemContainerStyle>
                        <ComboBox.ToolTip>
                            <ToolTip>Zoek op text of selecteer</ToolTip>
                        </ComboBox.ToolTip>
                    </ComboBox>
                </Grid>

            </StackPanel>
        </Grid>

        <Grid x:Name="MainContainer" ClipToBounds="True"
                       >
            <Viewbox>
                <ItemsControl x:Name="drawingsheet" ItemsSource="{Binding ElementName=cmbPlannen, Path=SelectedItem.Hotspots}"
                                Width="{StaticResource canvasWidth}"
                                Height="{StaticResource canvasHeight}"
                                MouseLeftButtonUp="drawingsheet_MouseLeftButtonUp"
                                MouseRightButtonDown="drawingsheet_MouseRightButtonDown"
                                MouseWheel="drawingsheet_MouseWheel"
                                MouseLeftButtonDown="drawingsheet_MouseLeftButtonDown"
                                MouseMove="drawingsheet_MouseMove"
                                Background="White"
                                >
                    <ItemsControl.ItemsPanel>
                        <ItemsPanelTemplate>
                            <Canvas Background="{Binding ElementName=cmbPlannen,Path=SelectedItem.Plan_image,Converter={StaticResource ResourceKey=bytesToBitmapImageConverter}}"
                                    Width="{StaticResource canvasWidth}" Height="{StaticResource canvasHeight}"  />
                        </ItemsPanelTemplate>
                    </ItemsControl.ItemsPanel>
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <customPolygon:CustomPolygon x:Name="currentPolygon" PointsPolygon="{Binding Hotspot_points}"
                                                          IsSelected="{Binding IsSelected,Mode=TwoWay}"
                                                          HasChildren="{Binding HasChildren}"></customPolygon:CustomPolygon>
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                    <ItemsControl.ItemContainerStyle>
                        <Style>
                            <Setter Property="Canvas.Top" Value="{Binding Path=Y}" />
                            <Setter Property="Canvas.Left" Value="{Binding Path=X}" />
                        </Style>
                    </ItemsControl.ItemContainerStyle>
                    <ItemsControl.RenderTransform>
                        <TransformGroup>
                            <ScaleTransform x:Name="scaleCanvas"></ScaleTransform>
                            <TranslateTransform x:Name="moveCanvas"></TranslateTransform>
                        </TransformGroup>
                    </ItemsControl.RenderTransform>
                </ItemsControl>
            </Viewbox>
        </Grid>

    </DockPanel>
</Grid>

My UserControl CustomPolygon.Xaml:

<UserControl x:Class="testCanvas.Controls.DrawingControls.CustomPolygon"
         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:i="http://schemas.microsoft.com/expression/2010/interactivity" 
         mc:Ignorable="d"
         Name="userControl"
        >
<Polygon x:Name="polygon"
         Points="{Binding ElementName=userControl,Path=PointsSource}"
         StrokeThickness="0.5"
         Stroke="Black"
         Opacity="0.5"            
         MouseEnter="polygon_MouseEnter"
         MouseLeave="polygon_MouseLeave"
         MouseLeftButtonDown="polygon_MouseLeftButtonDown"/>
    </UserControl>

My code behind from CustomPolygon

public partial class CustomPolygon : UserControl, INotifyPropertyChanged
{
    public CustomPolygon()
    {
        InitializeComponent();
    }

    #region Properties

    public bool IsSelected
    {
        get { return (bool)GetValue(IsSelectedProperty); }
        set
        {
            SetValue(IsSelectedProperty, value);
            if (IsSelected)
            {
                polygon.Stroke = Brushes.Red;
                polygon.StrokeThickness = 2;
            }
            else
            {
                polygon.Stroke = Brushes.Black;
                polygon.StrokeThickness = 0.5;
            }
        }
    }
    // Using a DependencyProperty as the backing store for IsSelected.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty IsSelectedProperty =
        DependencyProperty.Register("IsSelected", typeof(bool), typeof(CustomPolygon),
    new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

    //points for polygon
    public PointCollection PointsPolygon
    {
        get { return (PointCollection)GetValue(PointsPolygonProperty); }
        set { SetValue(PointsPolygonProperty, value); }
    }
    // Using a DependencyProperty as the backing store for PointsPolygon.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty PointsPolygonProperty =
        DependencyProperty.Register("PointsPolygon", typeof(PointCollection), typeof(CustomPolygon),
          new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));



    public bool HasChildren
    {
        get { return (bool)GetValue(HasChildrenProperty); }
        set { SetValue(HasChildrenProperty, value); }
    }

    // Using a DependencyProperty as the backing store for HasChildren.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty HasChildrenProperty =
        DependencyProperty.Register("HasChildren", typeof(bool), typeof(CustomPolygon),
        new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
    #endregion

    private void polygon_MouseEnter(object sender, MouseEventArgs e)
    {
        if (IsSelected != true)
        {
            polygon.Stroke = new SolidColorBrush((Color)ColorConverter.ConvertFromString(Properties.Settings.Default.HotspotHover));
            polygon.StrokeThickness = 1;
        }

    }

    private void polygon_MouseLeave(object sender, MouseEventArgs e)
    {
        if (IsSelected != true)
        {
            polygon.Stroke = Brushes.Black;
            polygon.StrokeThickness = 0.5;
        }
    }

    private void polygon_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        IsSelected = !IsSelected;
    }
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

Problem is now if i change my selection in cmbHotspot the property is not changing in my usercontrol and visa versa

Upvotes: 1

Views: 2824

Answers (1)

Clemens
Clemens

Reputation: 128077

What they are telling in this blog is not correct for WPF. The article is not about WPF and what it shows is not even necessary in Windows Runtime. You should definitely ignore the parts about setting the DataContext in the constructor of a custom control.

Anyway, you must not call anything else than SetValue in the setter of the CLR wrapper of a dependency property. See the XAML Loading and Dependency Properties article on MSDN for details.

Besides that a dependency property does not need to raise a PropertyChanged event, so your SetValueIsSelected property is redundant anyway.

Finally, your property metadata was wrong, because 0 is not a valid default value for type bool.

Your declaration should look like this:

public static readonly DependencyProperty IsSelectedProperty =
    DependencyProperty.Register(
        "IsSelected", typeof(bool), typeof(CustomPolygon));

public bool IsSelected
{
    get { return (bool)GetValue(IsSelectedProperty); }
    set { SetValue(IsSelectedProperty, value); }
}

Unless you don't want to set any non-standard property metadata, you don't need to specify the PropertyMetadata parameter of the Register method.

However, if you want that the property binds two-way by default, you have to set the appropriate flag by property metadata.

public static readonly DependencyProperty IsSelectedProperty =
    DependencyProperty.Register(
        "IsSelected", typeof(bool), typeof(CustomPolygon),
        new FrameworkPropertyMetadata(
            false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault);

Upvotes: 2

Related Questions