将字符串项绑定到 xaml 中字符串的依赖属性列表

Posted

技术标签:

【中文标题】将字符串项绑定到 xaml 中字符串的依赖属性列表【英文标题】:Binding string items to a dependency property list of strings in xaml 【发布时间】:2022-01-18 17:19:42 【问题描述】:

我有一个定义为依赖属性的字符串列表。我通过 xaml 分配列表项的值。我可以分配文字字符串值,但我不知道如何将这些值绑定到 viewmodel 中的数据。

public static readonly DependencyProperty StringArgsProperty = DependencyProperty.Register(
        "StringArgs", typeof(List<string>), typeof(GameTextBlock), new FrameworkPropertyMetadata(new List<string>()));

    public List<string> StringArgs
    
        get  return (List<string>)GetValue(StringArgsProperty); 
        set  SetValue(StringArgsProperty, value); 
    

以下是我目前如何将项目绑定到所述列表:

<common:GameTextBlock.StringArgs>
  <sys:String>arg1</sys:String>
  <sys:String>arg2</sys:String>
</common:GameTextBlock.StringArgs>

我想要做的是将 arg1/arg2 替换为 ViewModel 中的值。如果我没有分配给列表的项目,我可以执行“Binding NameOfField”。

我不想在 ViewModel 中创建整个列表并绑定列表,因为我希望能够仅使用 xaml 来挑选项目。这可以实现吗?

编辑:我想要实现的更清晰的示例:

public class ViewModel

   public string Item1 get; set;
   public string Item2 get; set;
   public string Item3 get; set;

然后我希望能够在一个包含多个 GameTextBlock 的 xaml 中使用它们,如下所示:

<GameTextBlock x:Name = "txt1" > 
<GameTextBlock.StringArgs>
  <sys:String>Binding VMItem1</sys:String>
  <sys:String>Binding VMItem3</sys:String>
</GameTextBlock.StringArgs>
</GameTextBlock>

<GameTextBlock x:Name = "txt2" > 
<GameTextBlock.StringArgs>
  <sys:String>Binding VMItem1</sys:String>
  <sys:String>Binding VMItem2</sys:String>
</GameTextBlock.StringArgs>
</GameTextBlock>

<GameTextBlock x:Name = "txt3" > 
<GameTextBlock.StringArgs>
  <sys:String>Binding VMItem1</sys:String>
</GameTextBlock.StringArgs>
</GameTextBlock>

【问题讨论】:

不要使用new FrameworkPropertyMetadata(new List&lt;string&gt;())。对于 GameTextBlock 的所有实例,它将是相同的列表。使用new FrameworkPropertyMetadata(null)并在构造函数中初始化StringArgs 最好在构造函数中通过SetCurrentValue(StringArgsProperty, new List&lt;string&gt;()) 来实现。 @user2396632:从哪里“挑选”什么项目?所有项目都应在视图模型中定义。 @mm8 视图模型中定义的项目。我可以通过在 GameTextBlock 中创建属性“Arg0、Arg1、Arg2...”然后像 一样分配它们来实现这一点。为每个 GameTextBlock 和绑定创建一个 List 对我来说效果不佳,因为有多个 GameTextBlock 重用相同的单个 Args,所以我真的想要一种在 xaml 中创建列表的方法,但绑定单个项目的值. 那么您想将视图模型中的项目与您在 XAML 中指定的项目结合起来吗? 【参考方案1】:

xaml 页面上的静态数据无法更改。将列表结构移动到依赖属性的更改处理程序后面和上的代码根据需要移动数据到属性列表。无论如何,这就是应该的方式。

如果您需要双向传输,那么您将需要更多代码来将数据从页面上的控制列表移回存储;不过,这可以用作模板。

后面的控制代码

数据列表

以下是自定义控件上要拆分到的列表:

public partial class ShowDependency : UserControl, INotifyPropertyChanged

 
private List<string> _Text1;

public List<string> Text1

    get  return _Text1; 
    set  _Text1 = value; OnPropertyChanged(nameof(Text1)); 


private List<string> _Text2;

public List<string> Text2

    get  return _Text2; 
    set  _Text2 = value; OnPropertyChanged(nameof(Text2)); 

带有 PropertyChanged 处理程序的依赖属性

这是保存来自 VM 的传入列表的依赖属性

#region public List<string> Storage
/// <summary>Storage is a transfer from the Main VM</summary>
public List<string> Storage

    get => (List<string>)GetValue(StorageProperty);
    set => SetValue(StorageProperty, value);


/// <summary>Identifies the Storage dependency property.</summary>
public static readonly DependencyProperty StorageProperty =
    DependencyProperty.Register(
        "Storage",
        typeof(List<string>),
        typeof(ShowDependency),
        new PropertyMetadata(null, OnStoragePropertyChanged));
更改处理程序

一旦绑定,它会将数据添加到列表中。

/// <summary>StorageProperty property changed handler.</summary>
/// <param name="d">ShowDependency that changed its Storage.</param>
/// <param name="e">Event arguments.</param>
private static void OnStoragePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)

    if (d is ShowDependency source)
    
        var value = (List<string>)e.NewValue;

        if (value != null)
        
            var l1 = new List<string>();
            var l2 = new List<string>();
            int count = 1;
            foreach (var item in value)
                if ((count++ % 2) == 0)
                    l1.Add(item);
                else 
                    l2.Add(item);

            source.Text1 = l1;
            source.Text2 = l2;
        

    

#endregion public List<string> Storage
主虚拟机上的字符串绑定列表
 new List<string>()  "Alpha", "Baker", "Tango", "Omega" 
自定义控制页面
<UserControl x:Class="ExamplesInWPF.Controls.ShowDependency"
             ...
             d:DesignHeight="450" d:DesignWidth="800"
             x:Name="MyUserControl">
    <StackPanel Orientation="Vertical">
        <ListBox Margin="6" ItemsSource="Binding Text1, ElementName=MyUserControl"/>
        <ListBox Margin="6" ItemsSource="Binding Text2, ElementName=MyUserControl"/>        
    </StackPanel>
</UserControl>
结果


顺便说一句,我一直使用这些 Control 依赖属性 sn-ps

Helpful Silverlight Snippets

忽略 Silverlight 部分,它们仍然很好,并且适用于 .Net 6 Xaml/WPF。

【讨论】:

以上是关于将字符串项绑定到 xaml 中字符串的依赖属性列表的主要内容,如果未能解决你的问题,请参考以下文章

TreeView ItemSsource 绑定到 ViewModel 不更新 xaml 控件项

WPF xaml中列表依赖属性的定义

将 GeometryDrawing 画笔绑定到自定义控件依赖属性

如何将对象及其属性绑定到树视图

将代码数据绑定到 XAML 透视列表框

为啥在数据模板中使用 xaml UserControl 时无法绑定到依赖属性? [复制]