wpf绑定到选定的列表视图项,并根据该选择更新另一个列表

时间:2017-08-14 15:48:23

标签: c# wpf listview mvvm

我正在使用Visual Studio 2015,我试图自学MVVM模式,而且我遇到了障碍。我的代码基于Josh Smiths的文章,我用它来帮助我学习MVVM并在此过程中创建一个小应用程序。

我想要完成的任务:
我已将viewmodel绑定到listview,显示产品列表,每个产品都有一个" productTemplate"项目。在我的视图中,当我选择列表视图中的产品时,我希望此列表填充在列表框中。我正在实现INotifyPropertyChanged。我想我只是错过了一些简单但我不确定的事情。

我的代码: 两个模型(Product,ProductTemplateItem);

public class Product  {

    private string _productNum;
    private string _productFamily;

    public Product() {    
    }

    public string ProductNum { get; set; }

    public string ProductFamily { get; set; }

}

public class ProductTemplateItem : ChangeEventHandlerBase {

    private string _TemplateItem;
    private string _TemplateCode;

    public ProductTemplateItem(string templateItem, string templateCode) {
        _TemplateItem = templateItem;
        _TemplateCode = templateCode;
    }

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

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

    public override string DisplayName {
        get {
            return $"{TemplateItem} - {TemplateCode}";
        }
    }
}

我的ViewModels(产品视图模型,将所有内容组合在一起并添加产品模板列表,AlProductsViewModel添加数据并公开要在XAML中绑定的所有内容):

public class ProductViewModel : BaseViewModel {

    private Product _product;
    private bool _isSelected;
    private List<ProductTemplateItem> _productTemplate;

    public ProductViewModel(string productNum, string productFamily) {
        Product.ProductNum = productNum;
        Product.ProductFamily = productFamily;
        _productTemplate = new List<ProductTemplateItem>();
    }

    public string ProductNumber {
        get { return _product.ProductNum; }
        set { if(_product.ProductNum != value) {
                _product.ProductNum = value;
                OnPropertyChanged("ProductNumber");
            }
        }
    }

    public string ProductFamily {
        get { return _product.ProductFamily; }
        set {
            if (_product.ProductFamily != value) {
                _product.ProductFamily = value;
                OnPropertyChanged("ProductFamily");
            }
        }
    }

    public bool IsSelected {
        get { return _isSelected; }
        set {
            if (_isSelected != value) {
                _isSelected = value;
                OnPropertyChanged("IsSelected");
            }
        }
    }

    public List<ProductTemplateItem> ProductTemplate {
        get { return _productTemplate; }
        set { if (_productTemplate != value) {
                _productTemplate = value;
                OnPropertyChanged("ProductTemplate");
            }
        }
    }

    public Product Product {
        get {
            if (_product == null) {
                _product = new Product();
                return _product;
            }
            else {
                return _product;
            }
        }
        set { if(_product != value) {
                _product = value;
                OnPropertyChanged("Product");
            }
        }
    }

    public override string DisplayName {
        get {
            return Product.ProductNum;
        }
    }

}

public class AllProductsViewModel : BaseViewModel{

    public AllProductsViewModel() {
        AddProducts();
    }

    private void AddProducts() {

        List<ProductViewModel> all = new List<ProductViewModel>();

        all.Add(new ProductViewModel("4835", "Crop Cart"));
        all.Add(new ProductViewModel("780", "Piler"));
        all.Add(new ProductViewModel("880", "Piler"));
        all.Add(new ProductViewModel("150", "Scooper"));

        all[0].ProductTemplate.Add(new Model.ProductTemplateItem("Miscellaneous","MISC"));
        all[0].ProductTemplate.Add(new Model.ProductTemplateItem("Drawbar", "DRBR"));
        all[0].ProductTemplate.Add(new Model.ProductTemplateItem("Mainframe", "FRAM"));
        all[0].ProductTemplate.Add(new Model.ProductTemplateItem("Conveyor", "CONV"));

        all[1].ProductTemplate.Add(new Model.ProductTemplateItem("Hello", "HELL"));

        AllProducts = new ObservableCollection<ProductViewModel>(all);

    }

    public ObservableCollection<ProductViewModel> AllProducts { get; private set; }

}

我的XAML代码是一个用户控件,其基于Josh代码的ListView和一个需要根据ListView中的选择进行更新的列表框:

<UserControl x:Class="Parts_Book_Tool.Views.ProductsView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:local="clr-namespace:Parts_Book_Tool.Views"
         xmlns:viewModel="clr-namespace:Parts_Book_Tool.ViewModel"
         xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">

<UserControl.DataContext>
    <viewModel:AllProductsViewModel/>
</UserControl.DataContext>

<UserControl.Resources>
    <CollectionViewSource x:Key="ProductGroups" Source="{Binding Path=AllProducts}">
        <CollectionViewSource.GroupDescriptions>
            <PropertyGroupDescription PropertyName="ProductFamily"/>
        </CollectionViewSource.GroupDescriptions>
        <CollectionViewSource.SortDescriptions>
            <scm:SortDescription PropertyName="ProductFamily" Direction="Ascending"/>
        </CollectionViewSource.SortDescriptions>
    </CollectionViewSource>

    <GroupStyle x:Key="ProductGroupStyle">
        <GroupStyle.HeaderTemplate>
            <DataTemplate>
                <TextBlock 
                    FontWeight="Bold"
                    Margin="1"
                    Padding="4,2,0,2"
                    Text="{Binding Path=Name}" 
                    />
            </DataTemplate>
        </GroupStyle.HeaderTemplate>
    </GroupStyle>
    <Style x:Key="MainHCCStyle" TargetType="{x:Type HeaderedContentControl}">
        <Setter Property="HeaderTemplate">
            <Setter.Value>
                <DataTemplate>
                    <Border 
                        Background="{StaticResource Brush_HeaderBackground}" 
                        BorderBrush="LightGray" 
                        BorderThickness="1" 
                        CornerRadius="5" 
                        Margin="4" 
                        Padding="4" 
                        SnapsToDevicePixels="True" 
                        >
                        <TextBlock 
                            FontSize="14"
                            FontWeight="Bold"
                            Foreground="White" 
                            HorizontalAlignment="Center"  
                            Text="{TemplateBinding Content}" 
                            />
                    </Border>
                </DataTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <Style x:Key="ProductItemsStyle" TargetType="{x:Type ListViewItem}">
        <!-- 
  Stretch the content of each cell so that we can 
  right-align text in the Total Sales column. 
  -->
        <Setter Property="HorizontalContentAlignment" Value="Stretch" />
        <!-- 
  Bind the IsSelected property of a ListViewItem to the 
  IsSelected property of a CustomerViewModel object.
  -->
        <Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}" />            
        <Style.Triggers>
            <MultiTrigger>
                <MultiTrigger.Conditions>
                    <Condition Property="ItemsControl.AlternationIndex" Value="1" />
                    <Condition Property="IsSelected" Value="False" />
                    <Condition Property="IsMouseOver" Value="False" />
                </MultiTrigger.Conditions>
                <Setter Property="Background" Value="#EEEEEEEE" />
            </MultiTrigger>
        </Style.Triggers>
    </Style>
</UserControl.Resources>

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="1*"/>
        <RowDefinition Height="1*"/>
    </Grid.RowDefinitions>
    <HeaderedContentControl Header="Model Info" Style="{StaticResource MainHCCStyle}" Grid.Row="0">
        <ListView  x:Name="lvModelNumbers" Margin="6,2,6,50" DataContext="{StaticResource ProductGroups}" 
                   ItemContainerStyle="{StaticResource ProductItemsStyle}" ItemsSource="{Binding}" >
            <ListView.GroupStyle>
                <StaticResourceExtension ResourceKey="ProductGroupStyle"/>
            </ListView.GroupStyle>
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="Model Number" Width="100" DisplayMemberBinding="{Binding Path=DisplayName}"/>
                </GridView>
            </ListView.View>
        </ListView>
    </HeaderedContentControl>
    <HeaderedContentControl Header="Model Template" Style="{StaticResource MainHCCStyle}" Grid.Row="1">
        <ListBox ItemsSource="{Binding SelectedItem/ProductTemplate, ElementName=lvModelNumbers}" Margin="6,2,6,50">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding DisplayName}"/>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </HeaderedContentControl>
</Grid>

我觉得我错过了更新列表框的事件捕获,但由于我对MVVM缺乏经验,我无法确定。我已尝试绑定到指定元素的SelectedItem,但这不起作用。如果我绑定&#34; AllProducts / ProductTemplate&#34;,我可以填充列表框,但它只给我第一个索引值,当我选择另一个产品时,它不会动态改变。

希望这是足够的信息,任何帮助将不胜感激。我喜欢学习MVVM,但是我很难理解。

谢谢,

1 个答案:

答案 0 :(得分:0)

尝试将ListBox绑定到ProductTemplate的{​​{1}}属性的SelectedItem属性:

ListView