首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >将ListView绑定到ObservableCollection和两个可视控件

将ListView绑定到ObservableCollection和两个可视控件
EN

Stack Overflow用户
提问于 2014-12-29 08:02:34
回答 3查看 3.1K关注 0票数 0

我想将一个ListView绑定到字符串的ObservableCollection,我想用两个可视控件(例如,前缀和这些字符串的后缀)中的数据来修改这些字符串。

一个简化的例子:

XAML:

代码语言:javascript
运行
复制
<TextBox Name="tbPrefix"/>
<TextBox Name="tbPostfix"/>

<ListView Name="lvTarget"/>

C#:

代码语言:javascript
运行
复制
public ObservableCollection<string> sources = GetFromSomewhere();

public IEnumerable<string> Items()
{
    foreach (var source in sources) 
    {
        yield return tbPrefix.Text + source + tbPostfix.Text;
    }
}

为了更新ListView,我目前只是在CollectionChanged事件上重置它的ItemsSource:

代码语言:javascript
运行
复制
void sources_CollectionChanged(...)
{
    lvTarget.ItemsSource = Items();
}

但是我也希望ListView被绑定到它的三个源中的任何一个:集合和前缀/后缀控件。我想我想要一个MultiBinding或MultiDataTrigger,但是我不能完全了解语法和所有我可以找到的将控件绑定到其他控件的例子,而我也有这个ObservableCollection作为源代码。

抱歉,这是我在WPF的第三天,我有点不知所措!谢谢!

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-12-29 08:55:23

可观察集合用于通知集合中的项何时更改,如添加、删除、移动等。如果您更改字符串中的文本,它将不会通知。WPF中的第一个最佳实践规则是使用ViewModel绑定属性,而不是后面的代码。您可以通过以下方法解决此问题:

1-创建一个名为SomethingViewModel的新类

2-添加所有需要绑定到视图的属性:

代码语言:javascript
运行
复制
public class SomethingViewModel : INotifyPropertyChanged
{
    private string _prefix;
    private string _postfix;

    public SomethingViewModel()
    {
        Sources = new ObservableCollection<string>(/*pass initial data of the list*/);
        Sources.CollectionChanged += (sender, args) => OnPropertyChanged("Items");
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName = null)
    {
        var handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }

    private ObservableCollection<string> Sources { get; set; }

    public IList<string> Items
    {
        get { return Sources.Select(x => string.Format("{0}{1}{2}", Prefix, x, Postfix)).ToList(); }
    }

    public string Prefix
    {
        get
        {
            return _prefix;
        }
        set
        {
            if (_prefix == value) return;
            _prefix = value;
            OnPropertyChanged("Prefix");
            OnPropertyChanged("Items");
        }
    }

    public string Postfix
    {
        get
        {
            return _postfix;
        }
        set
        {
            if (_postfix == value) return;
            _postfix = value;
            OnPropertyChanged("Postfix");
            OnPropertyChanged("Items"); // we will notify that the items list has changed so the view refresh its items
        }
    }
}

3-在视图的构造函数中,将以下代码插入视图的数据文本:

代码语言:javascript
运行
复制
public MainWindow()
{
    this.DataContext= new SomethingViewModel();
}

4-最后将视图元素绑定到视图模型属性:

代码语言:javascript
运行
复制
<TextBox Text={Binding Prefix,Mode=TwoWay}/>
<TextBox  Text={Binding Postfix,Mode=TwoWay}/>

<ListView ItemsSource={Binding Items}/>

5-如果要更改源中的项,不要初始化新对象,只需使用以下方法:

代码语言:javascript
运行
复制
Sources.Clear();
Sources.Add();
票数 1
EN

Stack Overflow用户

发布于 2014-12-29 08:55:04

免责声明:请注意,使用DataTemplate,如克莱门斯的答案,将是更好的解决方案,如果你只需要修改项目的视觉外观。如果您实际上希望将字符串组合成项,那么就按照ViewModel的方式进行。下面的解决方案不是最佳实践,它试图演示MultiBindings如何工作。

这个问题最好在您的ViewModel中解决。只有在绝对必要时才应使用转换器(特别是MultiConverters )。

但是由于这是你使用WPF的第三天,你还不应该被MVVM所困扰。

  1. 使窗口类本身成为DataContext: 公共MainWindow() { InitializeComponent();this.DataContext = this;} 这将允许我们使用从窗口到其上定义的属性的数据绑定。
  2. 我们可以为项使用默认属性,但是WPF不会注意到属性值何时发生变化。现在我们将使用DependencyProperty: 公共静态只读DependencyProperty ItemsProperty =DependencyProperty.Register(“项”、类型( IEnumerable )、类型(MainWindow));公共IEnumerable项{ get {get (IEnumerable) GetValue(ItemsProperty);} set { SetValue(ItemsProperty,value);} public MainWindow() { InitializeComponent();this.DataContext = this;this.Items = new[] {"sdf“、"fdsa”、"tgrg"}; 每当我们调用该属性的setter时,WPF将注意到它并更新到该属性的所有绑定。我们还更新了构造函数,以便最初加载一些值。 我们也可以实现INotifyPropertyChanged --事实上,ViewModels使用这种模式-和/或使用ObservableCollection。不幸的是,ObservableCollection更改不会重新触发MultiBinding,所以我们只使用IEnumerable<string>作为类型。
  3. 现在让我们在XAML中添加绑定: 好的,我们使用一个ItemsSource设置MultiBinding。这实际上是您在变更处理程序中所做的工作:每当它的一个子绑定发生更改时,它都会调用指定的转换器并使用其结果更新ItemsSource。但是这个PrefixPostfixConverter是什么
  4. 添加PrefixPostfixConverter类: 公共类PrefixPostfixConverter : IMultiValueConverter {公共对象转换(object[]值、类型targetType、对象参数、CultureInfo区域性){ if (值为== null = values.Length != 3)抛出新的ArgumentException(“值”);var items =值为IEnumerable;var前缀= values1作为字符串;var postfix = values2作为字符串;if (items == null +前缀== null values.Length!=3)返回空;返回items.Cast() .Select(i =>前缀+i+后缀) .ToArray();} public object[] ConvertBack(对象值、Type[] targetTypes、对象参数、CultureInfo区域性){抛出新NotSupportedException();} 这将从您的三个绑定(作为values参数传入)中获取输入,并将合并的值创建为数组。
票数 1
EN

Stack Overflow用户

发布于 2014-12-29 08:51:28

你不需要任何暗号。只需为DataTemplate项创建适当的ListView:

代码语言:javascript
运行
复制
<ListView ItemsSource="{Binding Items}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding Text, ElementName=tbPrefix}"/>
                <TextBlock Text="{Binding}"/>
                <TextBlock Text="{Binding Text, ElementName=tbPostfix}"/>
            </StackPanel>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

注意,Items在这里是一个公共属性,而不是一个方法,您应该在视图模型类中声明它。该视图模型类的一个实例将分配给视图的DataContext (例如,MainWindow)。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27685395

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档