Передача дополнительных аргументов в пользовательский элемент управления внутри шаблона данных

Это код xaml, который я использую

  <GridView
        Grid.Row="0"
        x:Name="RootGrid"
        SelectionMode="None"
        IsItemClickEnabled="True"
        ItemsSource="{Binding RootListSource}">

        <GridView.ItemTemplate>
            <DataTemplate>
                <UserControl:TreeInfoControl/>
            </DataTemplate>
        </GridView.ItemTemplate>

    </GridView>

в этом моем пользовательском элементе управления он содержит другой GridView, который содержит другую коллекцию IEnumerable. Я пытаюсь достичь того, что мне нужно передать эту коллекцию через код. Я попробовал это, добавив свойство зависимостей в treecontrol, но оно не работает. Поэтому я ищу решение, которое позволяет передавать коллекцию через xaml (каким-то образом через пользовательский элемент управления). Я знаю, что можно добавить, что коллекция к моей существующей коллекции и свяжите ее. Но сейчас я не могу использовать этот метод.

1 ответов


вот как вы это делаете.

начните с вашего приложения.xaml, чтобы мы могли повторно использовать демонстрационный шаблон

<Application.Resources>
    <DataTemplate x:Key="MyContentControl">
        <Grid Height="100" Width="100" Background="Maroon">
            <TextBlock Text="{Binding FallbackValue=0}" Foreground="White" FontSize="40" VerticalAlignment="Center" HorizontalAlignment="Center" />
        </Grid>
    </DataTemplate>
</Application.Resources>

тогда мы можем определить ваш пользовательский элемент управления

<d:UserControl.DataContext>
    <local:MyControlViewModel Number="-1" Letter="~K" />
</d:UserControl.DataContext>

<StackPanel Orientation="Horizontal" VerticalAlignment="Top" HorizontalAlignment="Left">
    <ContentControl Content="{Binding Number}" 
                    ContentTemplate="{StaticResource MyContentControl}" />
    <ListView ItemsSource="{Binding Letters}" IsHitTestVisible="False"
              ItemTemplate="{StaticResource MyContentControl}"
              SelectedItem="{Binding Letter, Mode=TwoWay}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <ItemsStackPanel Orientation="Horizontal"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ListView>
</StackPanel>

и затем мы можем определить вашу главную страницу.в XAML

<Page.DataContext>
    <local:MainPageViewModel Letter="C" />
</Page.DataContext>

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="140" />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <ListView x:Name="MyList" ItemsSource="{Binding Letters}" 
              ItemTemplate="{StaticResource MyContentControl}"
              SelectedItem="{Binding Letter, Mode=TwoWay}" />
    <ListView Grid.Column="1" ItemsSource="{Binding Numbers}">
        <ListView.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <StackPanel.Resources>
                        <local:MyControlViewModel 
                            x:Key="MyDataContext" Number="{Binding}" 
                            Letters="{Binding ItemsSource, ElementName=MyList}" 
                            Letter="{Binding SelectedItem, ElementName=MyList}" />
                    </StackPanel.Resources>
                    <local:MyControl DataContext="{StaticResource MyDataContext}" />
                </StackPanel>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</Grid>

пока ничего особенного, да? Ну, не так быстро. Мы создаем viewmodel для пользовательского элемента управления, устанавливая свойства модели представления из окружающей области, а затем передаем ее в DataContext пользовательского элемента управления явно. Круто, да? Достаточно просто, если подумать. Хотите установить эти свойства внутри тега? Уверен, что вы делаете. Но ты не можешь. Порядок действий был бы неправильным. Просто доверься мне.

теперь есть нулевой код для вашего пользовательского элемента управления. Но модель выглядит так:

public class MyControlViewModel : BindableBase
{
    public int Number
    {
        get { return (int)GetValue(NumberProperty); }
        set
        {
            SetValue(NumberProperty, value);
            base.RaisePropertyChanged();
        }
    }
    public static readonly DependencyProperty NumberProperty =
        DependencyProperty.Register("Number", typeof(int), typeof(MyControlViewModel),
        new PropertyMetadata(0, (s, e) => { }));

    public string Letter
    {
        get { return (string)GetValue(LetterProperty); }
        set
        {
            SetValue(LetterProperty, value);
            base.RaisePropertyChanged();
        }
    }
    public static readonly DependencyProperty LetterProperty =
        DependencyProperty.Register("Letter", typeof(string), typeof(MyControlViewModel),
        new PropertyMetadata("Z", (s, e) => { }));

    public ObservableCollection<string> Letters
    {
        get { return (ObservableCollection<string>)GetValue(LettersProperty); }
        set
        {
            SetValue(LettersProperty, value);
            base.RaisePropertyChanged();
        }
    }
    public static readonly DependencyProperty LettersProperty =
        DependencyProperty.Register("Letters", typeof(ObservableCollection<string>),
        typeof(MyControlViewModel),
        new PropertyMetadata(new ObservableCollection<string>(new[] { "~W", "~X", "~Y", "~Z" }), (s, e) => { }));
}

все свойства являются свойствами зависимостей. Надеюсь, вы заметили. Я сделал это не только потому, что люблю печатать. Хотя я люблю печатать. Дело в том, что я сделал это. потому что для внутренней привязки вы должны использовать свойство зависимостей - и свойство зависимостей, которое вызывает свойство изменено! Последняя часть не тривиальна. Но она должна быть в модели представления? Нет. Но мне это нравится.

вы можете ссылаться на это:http://blog.jerrynixon.com/2013/07/solved-two-way-binding-inside-user.html

также нет кода для вашей главной страницы. Но вид модели выглядит это:

public class MainPageViewModel : BindableBase
{
    public MainPageViewModel()
    {
        this._Letters = new ObservableCollection<string>(new[] { "A", "B", "C", "D" });
        this._Numbers = new ObservableCollection<int>(new[] { 1, 2, 3, 4 });
    }

    public string Letter
    {
        get { return (string)GetValue(LetterProperty); }
        set
        {
            SetValue(LetterProperty, value);
            base.RaisePropertyChanged();
        }
    }
    public static readonly DependencyProperty LetterProperty =
        DependencyProperty.Register("Letter", typeof(string), typeof(MyControlViewModel),
        new PropertyMetadata("Z", (s, e) => { }));

    ObservableCollection<string> _Letters = new ObservableCollection<string>();
    public ObservableCollection<string> Letters { get { return _Letters; } }

    ObservableCollection<int> _Numbers = new ObservableCollection<int>();
    public ObservableCollection<int> Numbers { get { return _Numbers; } }
}

связываемая база стандартная, вот код для нее:

public abstract class BindableBase : DependencyObject, System.ComponentModel.INotifyPropertyChanged
{

    public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
    protected void SetProperty<T>(ref T storage, T value, [System.Runtime.CompilerServices.CallerMemberName] String propertyName = null)
    {
        if (!object.Equals(storage, value))
        {
            storage = value;
            if (PropertyChanged != null)
                PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
        }
    }
    protected void RaisePropertyChanged([System.Runtime.CompilerServices.CallerMemberName] String propertyName = null)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
    }
}

когда все будет сделано, вы должны получить именно то, что вы хотите. Что-то вроде этого:--7-->

enter image description here

не слишком упрощать вещи. Но это так просто.

Послушайте, когда вы начинаете гнездить контексты, не всегда легко обернуть голову вокруг XAML. Я не виню тебя за то, что ты не сделал это с первого раза. Но я надеюсь, это поможет тебе начать. Держать толкает

удачи!