none
请问在 ControlTemplate 内部如何使用 DP 来指定 Binding 的 Path 属性? RRS feed

  • 问题

  • 我需要一个控件,功能就像一个有 Label 和一个输入框(也可能是 Combobox, 我希望这取决于控件模板)的控件,这个控件有两个 DP 属性,
    Path : 当前空间要绑定的属性
    Title : 当前字段的标题

    然后我在控件的 ControlTemplate 中放置了一个 TextBox, 我希望该 TextBox 数据绑定到当前控件的 Path 属性所指定的属性

    我尝试按下面的写法,结果当然是不行,我想知道,这种情况下,我应该怎样写?

    <ControlTemplate>
        <Grid>
            <Label Content="{TemplateBinding Title}" />
            <TextBox Text="{Binding Path={TemplateBinding Path}}" />
        </Grid>
    </ControlTemplate>

    1. 我应该如何写 TextBox 的 Text 的绑定语句?
    2. 如果我的方案本身就不可行,那么制作这样的控件应该如何完成?
    2009年7月1日 5:43

答案

  • 您好,

    -->我希望该 TextBox 数据绑定到当前控件的 Path 属性所指定的属性

     

     

    如果你是想简单绑定当前ControlPath属性的值,你可以用TemplateBinding 或是RelativeSource+FindAncestor语法,像你绑定Title一样。

    如果你想绑写Path指写的property来动态进行绑定,你可以用一个value converter来指定其需要绑写的属性,下面是一个例子。

     

    XAML code:

    <Window x:Class="WpfPathConverterTest.Window1"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        xmlns:local="clr-namespace:WpfPathConverterTest"

        Title="Window1" Height="300" Width="300">

        <Window.Resources>

            <local:PathValueConverter x:Key="converter" />

        </Window.Resources>

        <Grid>

            <local:CustomControl>

                <local:CustomControl.Template>

                    <ControlTemplate TargetType="local:CustomControl">

                        <StackPanel>

                            <Label Content="{TemplateBinding Title}" />

                             <!--1 use FindAncestor syntax-->

                            <TextBox Text="{Binding Path=Path, RelativeSource={RelativeSource TemplatedParent}}" />

                            <!--2 use value converter-->

                            <TextBox>

                                <TextBox.Text>

                                    <MultiBinding Converter="{StaticResource converter}">

                                        <Binding Mode="OneWay"   RelativeSource="{RelativeSource TemplatedParent}" />

                                        <Binding Path="Path" RelativeSource="{RelativeSource TemplatedParent}" />

                                    </MultiBinding>

                                </TextBox.Text>

                            </TextBox>

                        </StackPanel>

                    </ControlTemplate>

                </local:CustomControl.Template>

            </local:CustomControl>

        </Grid>

    </Window>

    In the code behind:

    using System;

    using System.Windows;

    using System.Windows.Controls;

    using System.Windows.Data;

    namespace WpfPathConverterTest

    {

        public partial class Window1 : Window

        {

            public Window1()

            {

                InitializeComponent();

            }

        }

        public class CustomControl : Control

        {

            public static readonly DependencyProperty TitleProperty =

                DependencyProperty.Register("Title", typeof(string), typeof(CustomControl), new FrameworkPropertyMetadata("DefaultTitle"));

            public static readonly DependencyProperty PathProperty =

              DependencyProperty.Register("Path", typeof(string), typeof(CustomControl), new FrameworkPropertyMetadata("DefaultPath"));

            public string Title

            {

                get { return (string)GetValue(TitleProperty); }

                set { SetValue(TitleProperty, value); }

            }

            public string Path

            {

                get { return (string)GetValue(PathProperty); }

                set { SetValue(PathProperty, value); }

            }

        }

        public class PathValueConverter : IMultiValueConverter

        {

            #region IMultiValueConverter Members

            public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)

            {

                CustomControl Control = new CustomControl();

                //you decide to return which property of Control according to the values[1], say the Path value

                //return a property value here

            }

            public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)

            {

                throw new NotImplementedException();

            }

            #endregion

        }

    }

     

    谢谢


    Jim Zhou -MSFT
    2009年7月3日 6:48
    版主

全部回复

  • 您好,

    -->我希望该 TextBox 数据绑定到当前控件的 Path 属性所指定的属性

     

     

    如果你是想简单绑定当前ControlPath属性的值,你可以用TemplateBinding 或是RelativeSource+FindAncestor语法,像你绑定Title一样。

    如果你想绑写Path指写的property来动态进行绑定,你可以用一个value converter来指定其需要绑写的属性,下面是一个例子。

     

    XAML code:

    <Window x:Class="WpfPathConverterTest.Window1"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        xmlns:local="clr-namespace:WpfPathConverterTest"

        Title="Window1" Height="300" Width="300">

        <Window.Resources>

            <local:PathValueConverter x:Key="converter" />

        </Window.Resources>

        <Grid>

            <local:CustomControl>

                <local:CustomControl.Template>

                    <ControlTemplate TargetType="local:CustomControl">

                        <StackPanel>

                            <Label Content="{TemplateBinding Title}" />

                             <!--1 use FindAncestor syntax-->

                            <TextBox Text="{Binding Path=Path, RelativeSource={RelativeSource TemplatedParent}}" />

                            <!--2 use value converter-->

                            <TextBox>

                                <TextBox.Text>

                                    <MultiBinding Converter="{StaticResource converter}">

                                        <Binding Mode="OneWay"   RelativeSource="{RelativeSource TemplatedParent}" />

                                        <Binding Path="Path" RelativeSource="{RelativeSource TemplatedParent}" />

                                    </MultiBinding>

                                </TextBox.Text>

                            </TextBox>

                        </StackPanel>

                    </ControlTemplate>

                </local:CustomControl.Template>

            </local:CustomControl>

        </Grid>

    </Window>

    In the code behind:

    using System;

    using System.Windows;

    using System.Windows.Controls;

    using System.Windows.Data;

    namespace WpfPathConverterTest

    {

        public partial class Window1 : Window

        {

            public Window1()

            {

                InitializeComponent();

            }

        }

        public class CustomControl : Control

        {

            public static readonly DependencyProperty TitleProperty =

                DependencyProperty.Register("Title", typeof(string), typeof(CustomControl), new FrameworkPropertyMetadata("DefaultTitle"));

            public static readonly DependencyProperty PathProperty =

              DependencyProperty.Register("Path", typeof(string), typeof(CustomControl), new FrameworkPropertyMetadata("DefaultPath"));

            public string Title

            {

                get { return (string)GetValue(TitleProperty); }

                set { SetValue(TitleProperty, value); }

            }

            public string Path

            {

                get { return (string)GetValue(PathProperty); }

                set { SetValue(PathProperty, value); }

            }

        }

        public class PathValueConverter : IMultiValueConverter

        {

            #region IMultiValueConverter Members

            public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)

            {

                CustomControl Control = new CustomControl();

                //you decide to return which property of Control according to the values[1], say the Path value

                //return a property value here

            }

            public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)

            {

                throw new NotImplementedException();

            }

            #endregion

        }

    }

     

    谢谢


    Jim Zhou -MSFT
    2009年7月3日 6:48
    版主
  • 谢谢!

    很感谢您的回复!

    在最终我使用的是如下的控件模板代码。

    <ControlTemplate x:Key="string_Input1" TargetType="{x:Type local:ValueInput}">
                    <Border Background="{TemplateBinding Background}"
                                BorderBrush="{TemplateBinding BorderBrush}"
                                BorderThickness="{TemplateBinding BorderThickness}">
                        <StackPanel Orientation="Horizontal" >
                            <Label Width="100"  HorizontalContentAlignment="Right"   ContentStringFormat="{}{0}:" Content="{TemplateBinding HeaderTitle}" />
                            <TextBox Width="200" Text="{Binding Path=BindingTo, RelativeSource = {RelativeSource AncestorType={x:Type local:ValueInput}}, Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}" />
                            <Label x:Name="labRequired" />
                        </StackPanel>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="Required" Value="True">
                            <Setter Property="Style" TargetName="labRequired" Value="{StaticResource IsRequired}" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>

    使用控件时用如下代码
    <local:mycontrol BindingTo="{Binding Path=xx}" />

    很高兴您的回复,谢谢!
    2009年7月6日 23:09