如何访问从ListBox WPF MVVM中选择的对象的属性

时间:2016-06-20 19:58:02

标签: c# wpf xaml mvvm listbox

我有一个列表框绑定到ViewModel中的可观察对象。当用户选择列表框中的项目时,SelectedItem将触发" SelectedSandwich"属性。该值将保存到私有字段。 SandwichName和Description属性是Sandwich对象的属性。我希望视图中的文本块显示选定的三明治名称和价格,但我不想将这些文本块绑定到列表框元素。 这是观点:     '

<Window.DataContext>
    <vm:SandwichVM/>
</Window.DataContext>

<Window.Resources>

    <DataTemplate x:Key="lstSandwich">
        <Border BorderThickness="3" 
                CornerRadius="4" 
                HorizontalAlignment="Stretch"
                BorderBrush="Blue">
            <TextBlock HorizontalAlignment="Stretch">
                <Run Text="{Binding SandwichName}"/>
                <Run Text=" | " />
                <Run Text="{Binding Description}" />
                <Run Text=" | " />
                <Run Text="{Binding Price}" />
            </TextBlock>
        </Border>
    </DataTemplate>

    <DataTemplate x:Key="menu" >
        <Border>
            <TextBlock HorizontalAlignment="Stretch">
                <Run Text="{Binding SandwichName}"/>
                <Run Text="{Binding Price}" />
            </TextBlock>  
        </Border>
    </DataTemplate>

</Window.Resources>

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="*" />
        <RowDefinition Height="2*"/>
    </Grid.RowDefinitions>

    <ListBox Grid.Row="0" x:Name="cboMenu" 
             ItemsSource="{Binding Sandwiches}"
             SelectedItem="{Binding SelectedSandwich, Mode=TwoWay}" 
             ItemTemplate="{StaticResource lstSandwich}"
             Margin="3">
    </ListBox>

    <Grid Grid.Row="1">
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="3*"/>
        </Grid.RowDefinitions>

        <TextBlock Grid.Row="0" 
                   HorizontalAlignment="Center" 
                   VerticalAlignment="Center" 
                   FontStretch="ExtraExpanded" 
                   FontFamily="Verdana"
                   FontSize="22"
                   >
            <Run Text="Your Selection"/>
        </TextBlock>
        <Grid Grid.Row="1">
            <ContentControl 
                ContentTemplate="{StaticResource menu}" 
                HorizontalAlignment="Stretch"
                Margin="5,0,5,0">
            </ContentControl>
           </Grid>
       </Grid>


   </Grid>
</Window>'

这是ViewModel:

'class SandwichVM : INotifyPropertyChanged
{
    private Sandwich _selectedSandwich;
    private ObservableCollection<Sandwich> _sandwiches;



    public ObservableCollection<Sandwich> Sandwiches 
    {
        get { return _sandwiches; }
    }


    public SandwichVM()
    {
        //fake data for the list
        _sandwiches = new ObservableCollection<Sandwich>();
        _sandwiches.Add(new Sandwich("Pastrami", "Stacked high on rye bread     with a touch of mustard.", 8.50));
        _sandwiches.Add(new Sandwich("Tuna", "Fresh tuna salad on wheat with slice of cheddar cheese.", 6.50));
        _sandwiches.Add(new Sandwich("Steak", "Sliced grilled steak with sauteed mushrooms and onions.", 9.50));
        _sandwiches.Add(new Sandwich("Chicken Salad", "Juicy chunks of chicken breast, onions, fruit.", 6.50));
        _sandwiches.Add(new Sandwich("Buffalo Chicken", "Caliente! Fried chicken breast slathered with hot buffalo wing sauce.", 8.50));
        _sandwiches.Add(new Sandwich("Tofu", "I don't know how to make a tofu sandwich.", 1.50));

    }

    public Sandwich SelectedSandwich
    {
        get { return _selectedSandwich; }
        set
        {
            if (_selectedSandwich != value)
            {
                _selectedSandwich = value;
                RaisePropertyChangedEvent("SelectedSandwich");
            }
        } 
    }

    public string SandwichName
    {
        get { return _selectedSandwich.SandwichName; }
        set
        {
            _selectedSandwich.SandwichName = value;
            RaisePropertyChangedEvent("SandwichName");
        }

    }

    public string Description
    {
        get { return _selectedSandwich.Description; }
        set
        {
            _selectedSandwich.Description = value;
            RaisePropertyChangedEvent("Description");
        }
    }

    public string Price
    {
        get { return _selectedSandwich.Price.ToString(); }
        set
        {
            _selectedSandwich.Price = Convert.ToDouble(value);
            RaisePropertyChangedEvent("Price");
        }
    }


    public event PropertyChangedEventHandler PropertyChanged;

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

我尝试将RaisePropertyChangedEvent放在三个属性的setter中(虽然我只需要读取它们)但是setter永远不会被执行。实际上,从不执行SelectedSandwich属性的setter。每次执行get。我已经完成了代码,但无法查看问题所在。 谢谢你的帮助。

1 个答案:

答案 0 :(得分:0)

也许我不清楚,但是你从UI设置的唯一属性是SelectedSandwich属性。如果在更改所选列表框项时它设置正确,那么为什么不从其他位置绑定到SelectedSandwich?

因此,如果您希望视图中的某些文本块显示选定的三明治名称和价格,请尝试以下内容:

<TextBlock Text="{Binding SelectedSandwich.Name}"/>
<TextBlock Text="{Binding SelectedSandwich.Price}"/>

或者如果您想使用准备好的datatemplate:

<DataTemplate DataType="{x:Type sandwichVMNamespace:Sandwich}">
    <Border>
        <TextBlock HorizontalAlignment="Stretch">
            <Run Text="{Binding SandwichName}"/>
            <Run Text="{Binding Price}" />
        </TextBlock>  
    </Border>
</DataTemplate>

<Grid Grid.Row="1">
   <ContentControl 
      Content="{Binding SelectedSandwich}" 
      HorizontalAlignment="Stretch"
      Margin="5,0,5,0">
   </ContentControl>
</Grid>

你完成了......