在 DataTemplate 中绑定控件属性的最佳实践?
Best practice for binding properties of controls within a DataTemplate?
我看到多年来有很多关于如何最好地绑定数据模板中的数据的问题,是否有最佳实践?在这种情况下,我希望我的 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>
如果想纯粹使用x:Bind,建议在XAML、Click="onButtonClicked"
中定义Click事件。在 View 中,您调用 ViewModel(在 MVVM 中,View 知道 VM)或者您可以发布一条消息,ViewModel 将捕获它并完成工作。 MVVM Light 有这个 Messenger 机制。
如果我对你的理解是正确的——你想复制与你点击的按钮一起的文本框的文本,而不是一些 selected\focused 文本框(否则没有意义,因为你有一个复制按钮对于列表视图中的每个项目)。如果是这样,只需使用命令:
<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);
}
}
我想你可以在你的MemoryItem
中绑定Button的Click事件,然后你就可以在这个事件中获取被点击按钮的数据上下文
为了测试,我在这里写了一个非常简单的demo:
<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 class:
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" });
}
}
内存项class:
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 可以用于事件,它在这里非常有用。
我看到多年来有很多关于如何最好地绑定数据模板中的数据的问题,是否有最佳实践?在这种情况下,我希望我的 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>
如果想纯粹使用x:Bind,建议在XAML、Click="onButtonClicked"
中定义Click事件。在 View 中,您调用 ViewModel(在 MVVM 中,View 知道 VM)或者您可以发布一条消息,ViewModel 将捕获它并完成工作。 MVVM Light 有这个 Messenger 机制。
如果我对你的理解是正确的——你想复制与你点击的按钮一起的文本框的文本,而不是一些 selected\focused 文本框(否则没有意义,因为你有一个复制按钮对于列表视图中的每个项目)。如果是这样,只需使用命令:
<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);
}
}
我想你可以在你的MemoryItem
中绑定Button的Click事件,然后你就可以在这个事件中获取被点击按钮的数据上下文
为了测试,我在这里写了一个非常简单的demo:
<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 class:
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" });
}
}
内存项class:
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 可以用于事件,它在这里非常有用。