从子控件绑定到父UserControl的DependencyProperty的更清洁方法

时间:2012-06-13 21:40:28

标签: .net wpf xaml ivalueconverter

我有一个带有自定义DependencyProperty的自定义UserControl。为了更好地描绘我如何使用它,UserControl是一个类似向导的控件中的左侧导航指示器。左导航控件存在于表示向导中的步骤的每个控件内部。在左侧导航控件的内部,我正在切换可见性并使用一些代码类似于以下代码的转换器设置几个子控件的可视属性。我不能使用简单的样式选择器或样式选择转换器,因为如果选择了项目,我的StackPanel中每行的整个结构是不同的。

这是一大堆代码,要重复我的控件以绑定到单个自定义属性。是否有以下更短的表格版本或更清晰的方式来实现这个?

<Polygon
    Visibility="{Binding
    RelativeSource={RelativeSource Mode=FindAncestor,
    AncestorType=UserControl},
    Path=Selected,
    Converter={StaticResource myCustomConverter},
    ConverterParameter='Expected String'}">
...

父视图提供单个属性来自定义子控件:

    <!-- Left Column -->
    <views:LeftNavControl Selected="Item to Select..." />

3 个答案:

答案 0 :(得分:1)

您可以做一些事情,但我不会将它们描述为实现它的更简洁/更短的方式。如果您使用MVVM方法,它们很容易实现。

您可以做的第一件事是删除绑定中的RelativeSource/AncestorType以找到绑定属性的位置。 如果您的所有控件(不清楚您使用了多少个控件)将共享相同的viewmodel,您可以将相同的viewmodel属性绑定到views:LeftNavControl.Selected,并绑定到所有切换的可见性控件。

你可以做的第二件事是更彻底的方法来清理你的xaml,它也会使你的myCustomConverter过时,但会在你的viewmodel中移动一些业务逻辑。如果您有大量Polygons /其他需要可见性切换的控件,这样做效果最佳。 您可以在viewmodel中拥有StepXVisiblity属性,并且每次views:LeftNavControl.Selected更改时您都可以计算它,并且您的Polygon(s)xaml将如下所示:

<Polygon Visibility="{Binding StepXVisiblity}">

上述解释的一个简单例子是:

<StackPanel>
    <TextBox Text="{Binding Step, UpdateSourceTrigger=PropertyChanged}" />
    <TextBlock Text="One" Visibility="{Binding StepOneVisible}" />
    <TextBlock Text="One" Visibility="{Binding StepOneVisible}" />
    <TextBlock Text="Two" Visibility="{Binding StepTwoVisible}" />
    <TextBlock Text="Two" Visibility="{Binding StepTwoVisible}" />
</StackPanel>

视图模型:

public class MyVM : DomainBase
{
    private int step;

    public int Step
    {
        get 
        { 
            return step; 
        }
        set 
        { 
            step = value;
            OnPropertyChanged("Step");
            OnPropertyChanged("StepOneVisible");
            OnPropertyChanged("StepTwoVisible");
        }
    }

    public Visibility StepOneVisible
    {
        get
        {
            return step == 1 ? Visibility.Visible : Visibility.Collapsed;
        }
    }

    public Visibility StepTwoVisible
    {
        get
        {
            return step == 2 ? Visibility.Visible : Visibility.Collapsed;
        }
    }
}

答案 1 :(得分:0)

唯一想到的是创建自己的绑定类,它派生自基本类(它本身就是标记扩展),并将所有这些属性设置为您通常使用的默认值。这样你只需要指定非默认的东西。

答案 2 :(得分:0)

首先,由于您在“导航”面板中说了一些内容,因此您可能需要考虑使用类似列表视图或列表框的内容,并在绑定到视图模型中的集合时模板化项目。但是,由于我不知道导航控件的范围,我将假设你的导航控件并不完全符合这个方案。

我建议使用附加属性来实现您所描述的基于单个父属性设置多个属性的内容。将以下内容视为伪代码,因为我还没有对其进行测试:

    public class MagicHelper
    {
        #region Super Property


        public static readonly DependencyProperty SuperProperty =
            DependencyProperty.RegisterAttached(
                "Super", typeof(SecretType), typeof(MagicHelper)
                new PropertyMetadata(-1, SuperChanged));

        // Get
        public static SecretType GetSuper(DependencyObject obj)
        {
            return (SecretType)obj.GetValue(SuperProperty);
        }

        // Set
        public static void SetSuper(DependencyObject obj, SecretType value)
        {
            obj.SetValue(SuperProperty, value);
        }

        // Change Event - make stuff happen here
        public static void SuperChanged(
            DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {

// I am using Polygon here for example but you could use a base class that might cover all your controls
            if (!(obj is Polygon))
                return;


            Polygon pGon = (Polygon)obj;

        // do your thing to pGon here with e.NewValue
        var mySecretInstance = e.NewValue as SecretType;

        if (mySecretInstance.frap)
        {
        pGon.Visibility = Visibility.Collapsed;
        pGon.Background = Brushes.Red;
            }

...
...

        }

}

并且XAML就是这样的

<UserControl Name="thisControl" 
xmlns:local="yourLibrary">
<Polygon local:MagicHelper.Super="{Binding ElementName=thisControl, Path=Selected"/>
...