0

I have a custom UserControl with a custom DependencyProperty. To paint a better picture of how I'm using this, the UserControl is the left navigation indicator in a wizard-like control. The left nav control exists inside of each of the controls that represent a step in the wizard. Inside of the left nav control, I am toggling visibility and setting visual properties of several child controls with a few converters with code similar to the following. I can't use a simple style selector or style-selecting converter because the entire structure of each row in my StackPanel is different if the item is selected or not.

This is a ton of code to be repeating all over my control to bind to a single custom property. Is there a shorter form version of the following or a cleaner way to implement this?

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

The parent views supply a single property to customize the child control:

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

3 に答える 3

1

There are some things you could do, but I would not describe them as neither a cleaner/shorter way to implement it. They are fairy easy to implement if you are using a MVVM approach.

The first thing you could do is getting rid of the RelativeSource/AncestorType in your bindings to find the location of the bound property. If both/all your controls (it's not clear how many controls you use) would share the same viewmodel you could bound the same viewmodel property to views:LeftNavControl.Selected, and to all of your toggled visibility controls.

The second thing you could do, is a more radical approach that would clean your xaml, and it will also make your myCustomConverter obsolete, but will move some of the business logic in your viewmodel. This works best in case you have a multitude of Polygons/other controls that need visibility toggle. You could have a StepXVisiblity property in your viewmodel, and you could calculate it every time views:LeftNavControl.Selected changes and your Polygon(s) xaml will look like:

<Polygon Visibility="{Binding StepXVisiblity}">

A simple example of the above explanation would be:

<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>

ViewModel:

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;
        }
    }
}
于 2012-06-13T22:27:42.043 に答える
0

まず、ナビゲーションパネルに沿って何かを言ったので、リストビューやリストボックスなどを使用して、ビューモデルのコレクションにバインドされているときにアイテムをテンプレート化することを検討することをお勧めします。ただし、Navコントロールの範囲がわからないため、Navコントロールがこのスキームに正確に適合していないと想定します。

添付プロパティを使用して、単一の親プロパティに基づいて複数のプロパティを設定すると説明したことを実現することをお勧めします。私はそれをテストしていないので、以下を擬似コードと考えてください:

    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"/>
...

m

于 2012-06-13T23:05:36.287 に答える
0

The only thing that comes to mind is to create your own binding class that derives from the base one (which itself is a markup extension) and sets all of those properties to the defaults you normally use. That way you will only have to specify the things that aren't default.

于 2012-06-13T22:18:56.920 に答える