简体   繁体   中英

Looking for guidance with MVVM textblock binding on mainviewmodel

I have an app that I'm working on relating to stocks.

It is fashioned somewhat like Josh Smith's MVVM demo app with some additions.

I have a data model called ShortQuote.cs which has a viewmodel ShortQuoteViewModel , but the ShortQuoteViewModel is not used right now.

I have a ShortQuoteRepository which creates a List of objects of type ShortQuote gotten from an XML data file. The ShortQuoteRepository List appears in a tab when the use clicks on a command on the left pane of the mainwindow.

I have a combobox on the MainWindow which has a list of ticker symbols. When the user selects one of these ticker symbols, I want to get one of the StockQuote objects from the ShortQuoteRepository (if it exists for that ticker) and display it's contents in TextBlocks at the top of the MainWindow view.

The only way I could get this to work was to expose "new" properties on MainWindowViewModel which are mirrors of the properties on the ShortQuote data model, then once I get the ShortQuote object from the ShortQuoteRepository I set the MainWindowViewModel 's "new" properties equal to those from the retrieved object. I bind the TextBlock's to the MainWindowViewModel 's "new" properties and it works.

I'm feeling like this is a "hack" and that there is a "better" way to accomplish this without having to create the "new" properties on the MainWindowViewModel and am requesting some guidance and suggestions on how to accomplish this in a more straightforward way with just XAML or a combination of XAML and MainWindowViewModel code that doesn't require creating these "new" properties.

Can anyone help me?

Also make your ShortQuote a ViewModel (or at least an ObservableObject, if you're using MVVM Light). Then you can bind SelectedItem to a ShortQuote property on your viewmodel (mark it as TwoWay). Then your View can reference the SelectedItem as it needs to.

Add this to ShortQuoteViewModel.cs

private ShortQuote _selectedQuote;

public ShortQuote SelectedQuote
{    
     get { return _selectedQuote; }
     set
     {
          if(value != _selectedQuote)
          {
               _selectedQuote = value;
               RaisePropertyChanged("SelectedQuote");
          }
      }
}

XAML:

<ListBox ItemsSource="{Binding Quotes}" SelectedItem={Binding SelectedQuote, Mode=TwoWay}"/>

<TextBlock Text="{Binding SelectedQuote.Ticker}"/>

You'll also have to change your ShortQuote class (probably in ShortQuote.cs ) to implement INotifyPropertyChanged , either by explicitly implementing INPC, or by inheriting from ViewModel or ObservableObject (if using MVVM Light. You didn't specify, but it's popular, and if you aren't using it, you should consider doing so).

EDIT Here's a working sample:

XAML:

<Window x:Class="StockQuoteExample.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="24"/>
            <RowDefinition/>
        </Grid.RowDefinitions>

        <TextBlock>
            <Run Text="Company Name: "/>
            <Run Text="{Binding SelectedTicker.Ticker}"/>
            <Run Text="  Symbol:  "/>
            <Run Text="{Binding SelectedTicker.StockName}"/>
            <Run Text="  Tick Price:  "/>
            <Run Text="{Binding SelectedTicker.TickPrice}"/>
        </TextBlock>

        <ListBox Grid.Row="1" Margin="10" ItemsSource="{Binding StockQuotes}" SelectedItem="{Binding SelectedTicker, Mode=TwoWay}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Width="120" Text="{Binding Ticker}"/>
                        <TextBlock Width="120" Margin="5,0,5,0" Text="{Binding StockName}"/>
                        <TextBlock Width="120" Text="{Binding TickPrice}"/>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Window>

Codebehind:

using System.Windows;
using StockQuoteExample.ViewModel;

namespace StockQuoteExample
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            this.DataContext = new StockQuoteViewModel();
        }
    }
}

ViewModel:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using StockQuoteExample.DataModel;

namespace StockQuoteExample.ViewModel
{
    class StockQuoteViewModel : INotifyPropertyChanged
    {

        public ObservableCollection<StockQuote> StockQuotes { get; set; }

        private StockQuote _selectedTicker;

        public StockQuote SelectedTicker
        {
            get { return _selectedTicker; }
            set
            {
                if (value != _selectedTicker)
                {
                    _selectedTicker = value;
                    OnPropertyChanged("SelectedTicker");
                }
            }
        }


        public StockQuoteViewModel()
        {
            StockQuotes = new ObservableCollection<StockQuote>()
                              {
                                  new StockQuote() {StockName = "Microsoft", TickPrice = 150m, Ticker = "MSFT"},
                                  new StockQuote() {StockName = "Apple", TickPrice = 600m, Ticker = "AAPL"}
                              };
        }




        public void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

    }
}

Data Model:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;

namespace StockQuoteExample.DataModel
{
    public class StockQuote : INotifyPropertyChanged
    {

        private string _ticker;

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

        private string _stockName;

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

        private decimal _tickPrice;

        public decimal TickPrice
        {
            get { return _tickPrice; }
            set
            {
                if (value != _tickPrice)
                {
                    _tickPrice = value;
                    OnPropertyChanged("TickPrice");
                }
            }
        }




        public void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM