首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >ListBox ItemTemplate -显示用户在运行时选择的属性。

ListBox ItemTemplate -显示用户在运行时选择的属性。
EN

Stack Overflow用户
提问于 2015-08-27 12:39:55
回答 3查看 86关注 0票数 1

我有一个ListBox,它绑定到List of DataModel

DataModel.cs

代码语言:javascript
运行
复制
public class DataModel
{
    public string Name { get; set; }
    public string Desc { get; set; }
    public string Code { get; set; }
}

ListBox应该显示两个属性,因此我已经将ItemTemplate定义如下

代码语言:javascript
运行
复制
<ListBox.ItemTemplate>
    <DataTemplate>
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="{Binding Name}"></TextBlock>
            <TextBlock Text=" - "></TextBlock>
            <TextBlock Text="{Binding Code}"></TextBlock>
        </StackPanel>
    </DataTemplate>
</ListBox.ItemTemplate>

我的要求是用户可以选择在运行时在ListBox中显示哪两个属性。我不知道如何做到这一点。我创建了一个示例解决方案来解释我的问题。

MainWindow.xaml

代码语言:javascript
运行
复制
<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
        </Grid.RowDefinitions>
        <StackPanel Orientation="Horizontal" Margin="5">
            <Label Content="Property One"></Label>
            <ComboBox Name="ComboBox1" Margin="3" Width="150" ItemsSource="{Binding DataModelProperties}"></ComboBox>
            <Label Content="Property Two"></Label>
            <ComboBox Name="ComboBox2" Margin="3" Width="150" ItemsSource="{Binding DataModelProperties}"></ComboBox>
            <Button Content="Go" Click="ButtonBase_OnClick" Margin="3"></Button>
        </StackPanel>
        <ListBox Grid.Row="1" ItemsSource="{Binding DataModelList}" Margin="5">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding Name}"></TextBlock>
                        <TextBlock Text=" - "></TextBlock>
                        <TextBlock Text="{Binding Code}"></TextBlock>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Window>

MainWindow.xaml.cs

代码语言:javascript
运行
复制
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;

namespace WpfApplication1
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            DataContext = new ViewModel();

        }

        private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
        {

        }
    }

    public class ViewModel
    {
        public List<String> DataModelProperties { get; set; }

        public List<DataModel> DataModelList { get; set; }

        public ViewModel()
        {
            DataModelList = new List<DataModel>();

            DataModelList.Add(new DataModel() { Name = "Name1", Code = "Code1", Desc = "Desc1" });
            DataModelList.Add(new DataModel() { Name = "Name2", Code = "Code2", Desc = "Desc2" });
            DataModelList.Add(new DataModel() { Name = "Name3", Code = "Code3", Desc = "Desc3" });

            DataModelProperties = typeof(DataModel).GetProperties().Select(s => s.Name).ToList();
        }
    }

    public class DataModel
    {
        public string Name { get; set; }
        public string Desc { get; set; }
        public string Code { get; set; }
    }
}

我试过的东西

代码语言:javascript
运行
复制
<TextBlock Text="{Binding ElementName=ComboBox1, Path=SelectedItem}"></TextBlock>

这只显示选定的属性名称。

EN

回答 3

Stack Overflow用户

发布于 2015-08-27 13:13:03

简而言之,我所做的是使两个公共属性绑定到并将您的属性更改为字段。此外,我还创建了自定义属性,以控制用户可以选择哪些字段。并创建了一个DisplayOptions类来存储选择,并将其扩展到DataModel实例。考虑到这是一个PoC,解决方案有点混乱,但我相信这可以做到:

XAML:

代码语言:javascript
运行
复制
  <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
        </Grid.RowDefinitions>
        <StackPanel Orientation="Horizontal" Margin="5">
            <Label Content="Property One"></Label>
            <ComboBox Name="ComboBox1" Margin="3" Width="150" ItemsSource="{Binding DataModelProperties}"></ComboBox>
            <Label Content="Property Two"></Label>
            <ComboBox Name="ComboBox2" Margin="3" Width="150" ItemsSource="{Binding DataModelProperties}"></ComboBox>
            <Button Content="Go" Click="ButtonBase_OnClick" Margin="3"></Button>
        </StackPanel>
        <ListBox Grid.Row="1" ItemsSource="{Binding DataModelList}" Margin="5">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding DisplayProperty1}"></TextBlock>
                        <TextBlock Text=" - "></TextBlock>
                        <TextBlock Text="{Binding DisplayProperty2}"></TextBlock>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>

政务司司长:

代码语言:javascript
运行
复制
 public partial class MainWindow : Window
    {
        public ViewModel model = new ViewModel();
        public MainWindow()
        {
            InitializeComponent();
            DataContext = model;
        }

        private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
        {
            //This part has to be on the View side, but this is PoC
            model.Opts.Prop1 = typeof(DataModel).GetFields()
                .Where(a => a.Name == ComboBox1.SelectedItem.ToString()).FirstOrDefault();
            model.Opts.Prop2 = typeof(DataModel).GetFields()
                .Where(a => a.Name == ComboBox2.SelectedItem.ToString()).FirstOrDefault();
            DataContext = null;
            DataContext = model;
        }
    }

    public class ViewModel
    {
        public DisplayOptions Opts = new DisplayOptions();

        public List<String> DataModelProperties { get; set; }

        public List<DataModel> DataModelList { get; set; }

        public ViewModel()
        {
            var properties = typeof(DataModel).GetFields()
              .Where(a => a.CustomAttributes.Any(b => b.AttributeType == typeof(SwitchableAttr)));

            //Initialising options before creating DataModel instances
            DataModelProperties = properties.Select(s => s.Name).ToList();
            Opts.Prop1 = properties.ElementAt(0);
            Opts.Prop2 = properties.ElementAt(1);


            DataModelList = new List<DataModel>();
            DataModelList.Add(new DataModel() { Name = "Name1", Code = "Code1", Desc = "Desc1", options = Opts });
            DataModelList.Add(new DataModel() { Name = "Name2", Code = "Code2", Desc = "Desc2", options = Opts });
            DataModelList.Add(new DataModel() { Name = "Name3", Code = "Code3", Desc = "Desc3", options = Opts });
        }
    }

    public class DisplayOptions
    {
        public FieldInfo Prop1;
        public FieldInfo Prop2;
    }

    public class DataModel
    {
        public DisplayOptions options;
        [SwitchableAttr]
        public string Name;
        [SwitchableAttr]
        public string Desc;
        [SwitchableAttr]
        public string Code;

        public string DisplayProperty1 { get { return (string)options.Prop1.GetValue(this); } set { } }
        public string DisplayProperty2 { get { return (string)options.Prop2.GetValue(this); } set { } }
    }

    public class SwitchableAttr : Attribute { }
票数 0
EN

Stack Overflow用户

发布于 2015-08-27 13:21:23

我建议您管理与ListBox中ViewModel中显示的“动态描述”有关的所有内容。

首先,视图模型和模型应该实现INotifyPropertyChanged。在我的示例中,我创建了一个实现它的简单基类。我的基类名为NotifyPropertyChangedImpl

此外,我在视图模型中添加了两个属性:用于选择属性的组合框绑定到这两个属性。

代码语言:javascript
运行
复制
public class ViewModel : NotifyPropertyChangedImpl
{
    private string property1;
    private string property2;

    public List<String> DataModelProperties { get; set; }

    public List<DataModel> DataModelList { get; set; }

    public string Property1
    {
        get
        {
            return property1;
        }
        set
        {
            if (property1 != value)
            {
                property1 = value;
                SetDynamicDescriptions();
            }
        }
    }

    public string Property2
    {
        get
        {
            return property2;
        }
        set
        {
            if (property2 != value)
            {
                property2 = value;
                SetDynamicDescriptions();
            }
        }
    }

    public ViewModel()
    {
        DataModelList = new List<DataModel>();

        DataModelList.Add(new DataModel() { Name = "Name1", Code = "Code1", Desc = "Desc1" });
        DataModelList.Add(new DataModel() { Name = "Name2", Code = "Code2", Desc = "Desc2" });
        DataModelList.Add(new DataModel() { Name = "Name3", Code = "Code3", Desc = "Desc3" });

        DataModelProperties = typeof(DataModel).GetProperties().Select(s => s.Name).ToList();
    }

    private void SetDynamicDescriptions()
    {
        PropertyInfo propertyInfo1;
        PropertyInfo propertyInfo2;

        Type type = typeof(DataModel);

        if (!String.IsNullOrEmpty(property1) && !String.IsNullOrEmpty(property2))
        {
            propertyInfo1 = type.GetProperty(property1);
            propertyInfo2 = type.GetProperty(property2);

            foreach (DataModel dataModel in DataModelList)
            {
                dataModel.DynamicDescription = String.Format("{0} - {1}",
                    propertyInfo1.GetValue(dataModel, null), propertyInfo2.GetValue(dataModel, null));
            }
        }
    }
}

如您所见,每次SetDynamicDescriptions或Property2更改时,Property1都会重新构建Property1。

我还向模型类添加了一个属性:

代码语言:javascript
运行
复制
public class DataModel : NotifyPropertyChangedImpl
{
    private string dynamicDescription;

    public string Name { get; set; }
    public string Desc { get; set; }
    public string Code { get; set; }

    public string DynamicDescription
    {
        get
        {
            return dynamicDescription;
        }
        set
        {
            if (dynamicDescription != value)
            {
                dynamicDescription = value;
                OnPropertyChanged("DynamicDescription");
            }
        }
    }
}

因此,到最后,您的XAML将是:

代码语言:javascript
运行
复制
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"></RowDefinition>
        <RowDefinition Height="*"></RowDefinition>
    </Grid.RowDefinitions>
    <StackPanel Orientation="Horizontal" Margin="5">
        <Label Content="Property One"></Label>
        <ComboBox Name="ComboBox1" Margin="3" Width="150" ItemsSource="{Binding DataModelProperties}"
                    SelectedItem="{Binding Property1}"></ComboBox>
        <Label Content="Property Two"></Label>
        <ComboBox Name="ComboBox2" Margin="3" Width="150" ItemsSource="{Binding DataModelProperties}"
                    SelectedItem="{Binding Property2}"></ComboBox>

    </StackPanel>
    <ListBox Grid.Row="1" ItemsSource="{Binding DataModelList}" Margin="5">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding DynamicDescription}" />
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</Grid>

我希望这能帮到你。

票数 0
EN

Stack Overflow用户

发布于 2015-08-27 13:33:12

这不是完整的MVVM,下面是代码

代码语言:javascript
运行
复制
public partial class MainWindow : Window
{
    private ViewModel vm;
    public MainWindow()
    {
        InitializeComponent();

        vm = new ViewModel();
        this.DataContext = vm;

    }

    private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
    {
        if (!string.IsNullOrEmpty(ComboBox1.Text) && !string.IsNullOrEmpty(ComboBox2.Text))
        {
            vm.AddDataToModel(ComboBox1.Text, ComboBox2.Text);
        }
    }
}

public class ViewModel
{
    public List<String> DataModelProperties { get; set; }


    private ObservableCollection<DataModel> _DataModelList;


    public ViewModel()
    {
        _DataModelList = new ObservableCollection<DataModel>();

        DataModelProperties = typeof(DataModel).GetProperties().Select(s => s.Name).ToList();
    }
    public void AddDataToModel(string cmbx1Val,string cmbx2Val)
    {
        _DataModelList.Add(new DataModel() { Name = cmbx1Val, Code = cmbx2Val, Desc = "Desc1" });
    }
    public ObservableCollection<DataModel> DataModelList
    {

        get
        {
            return _DataModelList;
        }
        set
        {
            _DataModelList = value;

        }

    }



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

https://stackoverflow.com/questions/32249662

复制
相关文章

相似问题

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