如何根据Wpf中的选定值从对象列表中获取值

时间:2017-11-23 08:17:14

标签: c# wpf mvvm

最后更新了一个简单示例

我有一个渲染到画布中的对象列表。该对象包含另一个基类

的对象
public class FooBase()
{
}

public class Foo1 : FooBase()
{
}

public class Foo2 : FooBase()
{
   public ICollection<Bar> BarList() { get;set; }
}

public class Bar
{
   public BarIdentifier BarIdentifier {get; set;}
   public int Value1 {get; set;}
   public string Value2 {get; set; }
}

public class HolderClass()
{
   public FooBase FooClass() { get; set; }

   public int PosX {get;set;}
   public int PosY {get;set;}
}

在我的模型中,我还有一个活跃的Bar类选择。这是通过使用下拉菜单设置的。我还有一个HolderClasses列表

public BarIdentifier SelectedBar {get;set;}

public List<ValveSystemOverviewGridContent> HolderList {get;set;}

在我的标记/ xaml中我有这个

<ItemsControl ItemsSource="{Binding HolderList}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemContainerStyle>
        <Style TargetType="ContentPresenter">
            <Setter Property="Canvas.Left" Value="{Binding Path=XPos, Mode=OneWay}" />
            <Setter Property="Canvas.Top" Value="{Binding Path=YPos, Mode=OneWay}" />
        </Style>
    </ItemsControl.ItemContainerStyle>
</ItemsControl>

和datatemplates as this

<UserControl.Resources>
    <DataTemplate DataType="{x:Type entities:Foo1 }" >
        <Border BorderBrush="Black" BorderThickness="1">
            <StackPanel Orientation="Horizontal" >
                <Label Content="FooClass 1" />
            </StackPanel>
        </Border>
    </DataTemplate>
    <DataTemplate DataType="{x:Type entities:Foo2 }">
        <Border CornerRadius="4" Background="White" BorderThickness="2" BorderBrush="{DynamicResource NormalBorderBrush}" >
            <StackPanel Orientation="Vertical">
                <Label Content="Foo Class 2" />

                <Label Content="{Binding ????" />
            </StackPanel>
        </Border>
    </DataTemplate>

    <DataTemplate DataType="{x:Type entities:HolderClass }">
        <StackPanel Orientation="Horizontal"  >
            <Label Content="This is Holder Class" FontWeight="Bold" />
            <ContentControl Content="{Binding Path=FooClass}" />
        </StackPanel>
    </DataTemplate>

</UserControl.Resources>

我想在FooBar2数据模板中做的是获取BarList中与SelectedBar匹配的项目之一。我通常会使用

来做这件事
BarList.First(b => b.BarIdentifier.Id == modelView.SelectedBar.Id);

有没有办法在我的数据模板中完成此过滤器/选择并以有效的方式显示Bar的Value1和Value2?

如果我更改主视图中的下拉列表,我想显示与BarIdentifier匹配的栏

使用示例更新

根据要求,我试着做一个简短的例子。包含函数GetCalcDataForCondition如何根据所选条件过滤掉CalcData。

MainWindow.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace FilterSample
{
    public class CalcData
    {
        public Condition Condition { get; set; }
        public int Diameter { get; set; }
        public string Name { get; set; }
    }
    public class Condition
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
    public class BaseClass
    {
        public string Name { get; set; }
    }

    class TagClass : BaseClass
    {
    }

    class ConnectionClass : BaseClass
    {
        public List<CalcData> CalcData { get; set; }
    }

    public class Holder
    {
        public int PosX { get; set; }
        public int PosY { get; set; }

        public BaseClass Content { get; set; }
    }


    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public List<Condition> Conditions { get; set; }
        public List<Holder> Holders { get; set; }

        public int SelectedConditionId { get; set; }

        private void GenerateData()
        {
            Conditions = new List<Condition>();
            Conditions.Add(new Condition() { Id = 1, Name = "Condition 1" });
            Conditions.Add(new Condition() { Id = 2, Name = "Condition 2" });
            Conditions.Add(new Condition() { Id = 3, Name = "Condition 3" });
            Conditions.Add(new Condition() { Id = 4, Name = "Condition 4" });
            Conditions.Add(new Condition() { Id = 5, Name = "Condition 5" });

            Holders = new List<Holder>();
            Holders.Add(new Holder() { PosX = 10, PosY = 10, Content = new TagClass() { } });
            Holders.Add(new Holder() { PosX = 10, PosY = 110, Content = GenerateConnectionClass(1, Conditions) });
            Holders.Add(new Holder() { PosX = 10, PosY = 210, Content = new TagClass() { } });
            Holders.Add(new Holder() { PosX = 10, PosY = 310, Content = GenerateConnectionClass(2, Conditions) });
            Holders.Add(new Holder() { PosX = 10, PosY = 410, Content = new TagClass() { } });
        }

        private ConnectionClass GenerateConnectionClass(int index, List<Condition> conditions)
        {
            var conn = new ConnectionClass();

            conn.Name = "Connection " + index;
            conn.CalcData = new List<CalcData>();
            foreach (var c in conditions)
            {
                conn.CalcData.Add(new CalcData() { Condition = c, Name = "Calc values for condition " + c.Id, Diameter = c.Id * 100 });
            }

            return conn;
        }

        private CalcData GetCalcDataForCondition(ConnectionClass conn, Condition condition)
        {
            return conn.CalcData.First(c => c.Condition.Id == condition.Id);
        }

        public MainWindow()
        {
            GenerateData();
            SelectedConditionId = 1;
            InitializeComponent();

            DataContext = this;
        }
    }
}

MainWindow.xaml

<Window x:Class="FilterSample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:FilterSample"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">

    <Window.Resources>
        <DataTemplate DataType="{x:Type local:TagClass }" >
            <Border BorderBrush="Black" BorderThickness="1">
                <StackPanel Orientation="Horizontal" >
                    <Label Content="Tag Class" />
                </StackPanel>
            </Border>
        </DataTemplate>
        <DataTemplate DataType="{x:Type local:ConnectionClass }">
            <Border CornerRadius="4" Background="White" BorderThickness="2" BorderBrush="{DynamicResource NormalBorderBrush}" >
                <StackPanel Orientation="Vertical">
                    <Label Content="Connection Class" />

                    <Label Content="HERE I WANT TO DISPLAY related CalcData.Name" />
                </StackPanel>
            </Border>
        </DataTemplate>

        <DataTemplate DataType="{x:Type local:Holder }">
            <StackPanel Orientation="Horizontal"  >
                <Label Content="This is Holder Class" FontWeight="Bold" />
                <ContentControl Content="{Binding Path=Content}" />
            </StackPanel>
        </DataTemplate>

    </Window.Resources>

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="50" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>

        <StackPanel Orientation="Horizontal">
            <Label Content="Select condition " Height="24" />
            <ComboBox ItemsSource="{Binding Conditions}" SelectedValue="{Binding SelectedConditionId}" DisplayMemberPath="Name" SelectedValuePath="Id" Width="200" Height="24" />

        </StackPanel>

        <ItemsControl ItemsSource="{Binding Holders}" Grid.Row="1">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Canvas />
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemContainerStyle>
                <Style TargetType="ContentPresenter">
                    <Setter Property="Canvas.Left" Value="{Binding Path=PosX , Mode=OneWay}" />
                    <Setter Property="Canvas.Top" Value="{Binding Path=PosY, Mode=OneWay}" />
                </Style>
            </ItemsControl.ItemContainerStyle>
        </ItemsControl>
    </Grid>
</Window>

1 个答案:

答案 0 :(得分:1)

基本上,您需要一些方式将所选条件ID传输到内部数据模板。我的建议:让DataTemplate的{​​{1}}取决于所选条件(将其从资源移至内容Holder)并为<ItemsControl.ItemTemplate>创建UserControl 。将Holder添加到usercontrol并分配它:

SelectedConditionId

将您的大部分内容移至持有人控件中,并使用<Window ...> <Grid x:Name="grid1"> <Grid.RowDefinitions> <RowDefinition Height="50" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <StackPanel Orientation="Horizontal"> <Label Content="Select condition " Height="24" /> <ComboBox x:Name="condSelector" ItemsSource="{Binding Conditions}" SelectedValue="{Binding SelectedConditionId}" DisplayMemberPath="Name" SelectedValuePath="Id" Width="200" Height="24" /> </StackPanel> <ItemsControl ItemsSource="{Binding Holders}" Grid.Row="1"> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <Canvas /> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemContainerStyle> <Style TargetType="ContentPresenter"> <Setter Property="Canvas.Left" Value="{Binding Path=PosX , Mode=OneWay}" /> <Setter Property="Canvas.Top" Value="{Binding Path=PosY, Mode=OneWay}" /> </Style> </ItemsControl.ItemContainerStyle> <!-- Here it is --> <ItemsControl.ItemTemplate> <DataTemplate> <local:HolderControl DataContext="{Binding}" SelectedConditionId="{Binding ElementName=condSelector,Path=SelectedValue}"/> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> </Grid> </Window> SelectedConditionId来获取所选MultiBinding

CalcData

代码背后:

<UserControl
        ....
        x:Name="uc1">
    <UserControl.Resources>

        <local:SelectedCalcDataConverter x:Key="calcDataSelector"/>

        <DataTemplate DataType="{x:Type local:TagClass }" >
            <Border BorderBrush="Black" BorderThickness="1">
                <StackPanel Orientation="Horizontal" >
                    <Label Content="Tag Class" />
                </StackPanel>
            </Border>
        </DataTemplate>
        <DataTemplate DataType="{x:Type local:ConnectionClass }">
            <Border CornerRadius="4" Background="White" BorderThickness="2" BorderBrush="{DynamicResource NormalBorderBrush}" >
                <StackPanel Orientation="Vertical">
                    <StackPanel.DataContext>
                        <MultiBinding Converter="{StaticResource calcDataSelector}" Mode="OneWay">
                            <Binding Path="CalcData"/>
                            <Binding ElementName="uc1" Path="SelectedConditionId"/>
                        </MultiBinding>
                    </StackPanel.DataContext>
                    <Label Content="Connection Class" />

                    <!--Label Content="HERE I WANT TO DISPLAY related CalcData.Name" /-->
                    <Label Content="{Binding Name}"/>
                </StackPanel>
            </Border>
        </DataTemplate>

    </UserControl.Resources>
    <Grid>
        <StackPanel Orientation="Horizontal"  >
            <Label Content="This is Holder Class" FontWeight="Bold" />
            <ContentControl Content="{Binding Path=Content}" />
        </StackPanel>
    </Grid>
</UserControl>

转换器:

public partial class HolderControl : UserControl
{
    public HolderControl()
    {
        InitializeComponent();
    }


    public int? SelectedConditionId
    {
        get { return (int?)GetValue(SelectedConditionIdProperty); }
        set { SetValue(SelectedConditionIdProperty, value); }
    }

    // Using a DependencyProperty as the backing store for SelectedConditionId.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty SelectedConditionIdProperty =
        DependencyProperty.Register("SelectedConditionId", typeof(int?), typeof(HolderControl), new FrameworkPropertyMetadata());
}

还有其他方法来传输选定的ID,但这个方法相对容易理解。