在DataTemplate中绑定控件属性的最佳实践?

时间:2016-04-21 20:17:26

标签: wpf win-universal-app uwp-xaml

我看到多年来一直有很多问题,关于如何最好地与数据模板中的数据绑定,是否有最佳实践?在这种情况下,我希望我的MemoryCopyBtn复制当前所选MemoryListItem TextBox的文本,以便我可以在ViewModel中对它进行处理。

我可以使用Findname找到ListView,但它会在PageLoad上为ListViewItem显示null。

我可以将所有内容都放在内存模型页面中,但我不认为这是最佳做法。

我看到这是走遍可视代码树的各种选项,但我想在运行时这样做,这真的是唯一的方法吗?

我有什么选择? 谢谢。

<ListView x:Name="ClipboardList"
                      xmlns:m="using:QuickieEdit.Models"
                      ItemsSource="{x:Bind ViewModel.MemoryItems}">
                <ListView.ItemTemplate>
                    <DataTemplate x:DataType="m:MemoryItem">
                            <StackPanel Orientation="Horizontal">
                                <Button x:Name="MemoryCopyBtn"
                                             Content="Copy"
                                             Click="How to Copy currently selected
                                             MemoryListItem.Text?"/> 
                                <TextBox x:Name="MemoryListItem"
                                               Text="{x:Bind Memory, Mode=TwoWay}">
                               </TextBox>                                  
                           </StackPanel>
                    </DataTemplate>
                </ListView.ItemTemplate>
</ListView>

3 个答案:

答案 0 :(得分:1)

如果我理解正确 - 你想复制文本框的文本,它与你点击的按钮一起,而不是一些选定的\聚焦文本框(否则没有意义,因为你有一个复制按钮为每个项目你的列表视图)。如果是这样,只需使用命令:

    <ListView.ItemTemplate>
        <DataTemplate x:DataType="m:MemoryItem">
            <StackPanel Orientation="Horizontal">
                <Button x:Name="MemoryCopyBtn"
                        Content="Copy"
                        Command="{Binding CopyCommand}"
                        CommandParameter="{Binding ElementName=MemoryListItem, Path=Text}" />
                <TextBox x:Name="MemoryListItem"
                         Text="{x:Bind Memory, Mode=TwoWay}"></TextBox>
            </StackPanel>
        </DataTemplate>
    </ListView.ItemTemplate>

在你的MemoryItem中:

public class MemoryItem {
    public MemoryItem() {
        CopyCommand = new RelayCommand(Copy);
    }        

    public string Memory { get; set; }
    public ICommand CopyCommand { get; private set; }

    private void Copy(object argument)
    {
        var text = (string)argument;
        Console.WriteLine(text);
    }
}

答案 1 :(得分:1)

我认为您可以在MemoryItem中绑定Button的Click事件,然后您可以获取此事件中单击按钮的数据上下文。

为了测试,我在这里写了一个非常简单的演示:

<ListView x:Name="ClipboardList" ItemsSource="{x:Bind ViewModel.MemoryItems}">
    <ListView.ItemTemplate>
        <DataTemplate x:DataType="local:MemoryItem">
            <StackPanel Orientation="Horizontal">
                <Button x:Name="MemoryCopyBtn"
                                     Content="Copy"
                                     Click="{x:Bind MemoryCopyBtn_Click}" />
                <TextBox x:Name="MemoryListItem"
                                       Text="{x:Bind Memory, Mode=TwoWay}">
                </TextBox>
            </StackPanel>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

代码背后:

private MainPageViewModel ViewModel;

public MainPage()
{
    this.InitializeComponent();
    ViewModel = new MainPageViewModel();
}

我的MainPageViewModel类:

public class MainPageViewModel
{
    public ObservableCollection<MemoryItem> MemoryItems;

    public MainPageViewModel()
    {
        MemoryItems = new ObservableCollection<MemoryItem>();
        MemoryItems.Clear();
        MemoryItems.Add(new MemoryItem { Memory = "Item 1" });
        MemoryItems.Add(new MemoryItem { Memory = "Item 2" });
        MemoryItems.Add(new MemoryItem { Memory = "Item 3" });
        MemoryItems.Add(new MemoryItem { Memory = "Item 4" });
        MemoryItems.Add(new MemoryItem { Memory = "Item 5" });
        MemoryItems.Add(new MemoryItem { Memory = "Item 6" });
        MemoryItems.Add(new MemoryItem { Memory = "Item 7" });
        MemoryItems.Add(new MemoryItem { Memory = "Item 8" });
    }
}

MemoryItem类:

public class MemoryItem
{
    public string Memory { get; set; }

    public void MemoryCopyBtn_Click(object sender, RoutedEventArgs e)
    {
        var item = ((FrameworkElement)e.OriginalSource).DataContext as MemoryItem;
        var text = item.Memory;
    }
}

这里的代码与你的100%相同,非常简单,只是为了测试,请不要介意。在一般情况下,我们避免使用VisualTree Helper来完成这项工作,x:Bind可以用于事件,它在这里非常有用。

答案 2 :(得分:0)

如果你想纯粹使用x:Bind,我建议你在XAML中定义Click事件,Click="onButtonClicked"。在View中,您调用ViewModel(在MVVM中,View知道VM)或者您可以发布消息,ViewModel将捕获它并执行工作。 MVVM Light有这种Messenger机制。