UserControl со свойствами зависимости, чтобы заменить повторяющийся набор похожих элементов управления - PullRequest
1 голос
/ 27 июля 2011

Извините за ужасный заголовок вопроса, я не знаю, как это сформулировать, не стесняйтесь комментировать.

Я работаю над настольным приложением WPF, используя шаблон MVVM. В моей ViewModel у меня есть большое количество текстовых полей, все из которых я хочу отобразить, используя приведенный ниже шаблон (значительно упрощенный):

<StackPanel Orientation="Vertical">
    <StackPanel.Style>
        <Style TargetType="{x:Type StackPanel}">
            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=SomePredicate}" Value="False">
                    <Setter Property="Visibility" Value="Collapsed"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </StackPanel.Style>

    <Label Content="SomeHeader:"/>

    <TextBlock Text="{Binding Path=SomeText}" />

</StackPanel>

Дисплей всегда состоит из:

  • Предикат для определения, должна ли отображаться StackPanel
  • Строка, используемая в качестве текста заголовка. Это может быть установлено в XAML, оно не должно исходить из модели представления
  • Привязка к текстовой строке Textblock в ViewModel

Мне бы очень хотелось иметь возможность определить их следующим образом:

<MyHeaderedTextBlockControl Text="{Binding Path=SomeText}"
                            Header="SomeHeader:"
                            Predicate="{Binding SomePredicate}"/>

Можно ли это сделать? Я пытался сделать это с помощью UserControl, но понятия не имел, что я делаю.

Для меня важно, чтобы режимы привязки продолжали работать, то есть, если привязка Text находится в режиме OneWay или TwoWay, TextBlock должно обновляться, когда свойство Text в ViewModel повышается OnPropertyChanged.

Мне также не нравится идея сделать это с помощью View и ViewModel для каждого такого текстового свойства, потому что тогда мне нужно создать эти ViewModel и подключить их для обновлений и т. Д. Мне нужно решение, которое я могу реализовать в View, в идеале ViewModel даже не должен знать об этом.

1 Ответ

2 голосов
/ 27 июля 2011

С помощью UserControls вы определяете свойства зависимостей в своем коде и перенаправляете их в «шаблон» через привязку, например ::

<UserControl x:Class="Test.UserControls.HeaderedTextBlock"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             Name="control">
    <StackPanel Orientation="Vertical">
        <StackPanel.Style>
            <Style TargetType="{x:Type StackPanel}">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Predicate, ElementName=control}" Value="False">
                        <Setter Property="Visibility" Value="Collapsed" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </StackPanel.Style>
        <Label Content="{Binding Header, ElementName=control}" />
        <TextBlock Text="{Binding Text, ElementName=control}" />
    </StackPanel>
</UserControl>
namespace Test.UserControls
{
    public partial class HeaderedTextBlock : UserControl
    {

        public static readonly DependencyProperty HeaderProperty =
            DependencyProperty.Register("Header", typeof(string), typeof(HeaderedTextBlock), new UIPropertyMetadata(null));
        public string Header
        {
            get { return (string)GetValue(HeaderProperty); }
            set { SetValue(HeaderProperty, value); }
        }

        public static readonly DependencyProperty PredicateProperty =
            DependencyProperty.Register("Predicate", typeof(bool), typeof(HeaderedTextBlock), new UIPropertyMetadata(false));
        public bool Predicate
        {
            get { return (bool)GetValue(PredicateProperty); }
            set { SetValue(PredicateProperty, value); }
        }

        public static readonly DependencyProperty TextProperty =
            DependencyProperty.Register("Text", typeof(string), typeof(HeaderedTextBlock), new UIPropertyMetadata(null));
        public string Text
        {
            get { return (string)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }

        public HeaderedTextBlock()
        {
            InitializeComponent();
        }
    }
}

Будет ли что-то подобное для вас?

...