Daniel Maurer
Daniel Maurer

Reputation: 166

C# WPF Binding Dictionary to Listview

I am on my first bigger WPF Program, many Windows and ViewModel, and could help myself just fine until now.
At first i had 2 List, one List<double> Factor, one List<string> Name, and I tried to bind both to one ListView. It didn't work, and I thought a Dictionary would be better.

So now I have a Dictionary<string, double> IngList = new Dictionary<string, double>(); After Clicking a Button the Content of 2 TextBox should get added to the Dictionary and then Displayed on my ListView.

(Just a small portion of the Code, else it would take up to much space)

My ViewModel:

namespace FoodsLib.ViewModel
{
    public class ViewModelAddRecipeWindow : ViewModelBase, INotifyPropertyChanged
    {

        public ViewModelAddRecipeWindow( IViewControl vctrl) 
        {
                AddIngredientCmd = new RelayCommand(() => AddToList() 
                _viewControl = vctrl;
                }
        }

        protected IViewControl _viewControl;



   new public event PropertyChangedEventHandler PropertyChanged;

        new protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = this.PropertyChanged;
            if (handler != null)
            {
                var e = new PropertyChangedEventArgs(propertyName);
                handler(this, e);
            }
        }

        protected string _ingredientR, _name, _stringtype, _stringCategory, _recipe;

            public double Factor
            {
                get { return _factor; }
                set
                {
                    if (_factor != value)
                    {
                        _factor = value;
                        OnPropertyChanged("Factor");
                    }
                }
            }

            public string IngredientR
            {
                get { return _ingredientR; }
                set
                {
                    if (_ingredientR != value)
                    {
                        _ingredientR = value;
                        this.OnPropertyChanged("IngredientR");
                    }
                }
            }

            Dictionary<string, double> IngList = new Dictionary<string, double>();


    public void AddToList()
            {

                if (!IngList.ContainsKey(IngredientR))
                {
                    IngList.Add(IngredientR, Factor);
                    _viewControl.ShowMessage("Added", "Ingredient");
                }
                else
                {
                    _viewControl.ShowMessage("You can't add an Ingredient twice", "Ingredient Error.");
                    return;
                }

            }

        public ICommand AddIngredientCmd { get; set; }
      }
}

And my View:

 <Grid Grid.Row="2" Grid.Column="3" HorizontalAlignment="Left" 
                  Margin="5,5,5,5" Grid.ColumnSpan="2" Grid.RowSpan="6">
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="100"></ColumnDefinition>
                    <ColumnDefinition Width="240"></ColumnDefinition>
                </Grid.ColumnDefinitions>
                <TextBox x:Name="tbAddFood" Grid.Row="0" Grid.Column="1" Text="{Binding IngredientR, Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}"  
                     Width="160" Margin="5" HorizontalAlignment="Left"/>
                <TextBox x:Name="tbAddFoodAmount" Grid.Row="1" Grid.Column="1" Text="{Binding Factor, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"  
                     Width="50" Margin="5" HorizontalAlignment="Left"/>

                <Label Grid.Row="0" Grid.Column="0" Content="Ingredients"  HorizontalAlignment="Right"
                   Margin="5" Foreground="#ebeff4"/>
                <Label Grid.Row="1" Grid.Column="0" Content="Amount"  HorizontalAlignment="Right"
                   Margin="5" Foreground="#ebeff4"/>



                <Button x:Name="btAddIngredient" Grid.Row="1" Grid.Column="1"
                Command="{Binding Path=AddIngredientCmd}" Content=" Add "  Margin="5,5,30,5" 
                    BorderBrush="#415578" BorderThickness="0" 
                    HorizontalAlignment="Center" Background="#415578" Foreground="#ebeff4"/>

                <ListView x:Name="lbFoodList" Grid.Column="1" Grid.Row="2"  Margin="5" Height="120" VerticalAlignment="Top"
                         Foreground="#ebeff4" ItemsSource="{Binding IngList}"
                                         ScrollViewer.VerticalScrollBarVisibility="Visible" Grid.RowSpan="4">
                    <ListView.View>
                        <GridView>
                            <GridView.ColumnHeaderContainerStyle>
                                <Style>
                                    <Setter Property="FrameworkElement.Visibility" Value="Collapsed"/>
                                </Style>
                            </GridView.ColumnHeaderContainerStyle>
                            <GridViewColumn Width="Auto" DisplayMemberBinding="{Binding Key, Mode=OneWay}"></GridViewColumn>
                            <GridViewColumn Width="Auto" DisplayMemberBinding="{Binding Value, Mode=OneWay}"></GridViewColumn>
                        </GridView>
                    </ListView.View>
                </ListView>

            </Grid>

I get to the point where the Dictionary gets filled with both items, but the ListView won't display anything.

I am not asking for a complete Code, just a "how" and "why". TY

Edit:

Using an ObservableCollection did the trick.

public ObservableCollection<tempIng> _ListMF = new
ObservableCollection<tempIng>();
        public ObservableCollection<tempIng> ListMF
        {
            get { return _ListMF; }
            set { _ListMF = value; OnPropertyChanged("_ListMF"); }
        }

with a new Class tempIng, which gets the Name and Factor after clicking "Add".

public class tempIng
{
    public string Name { get; set; }

    public double Factor { get; set; }

    public override string ToString()
    {
        return this.Name + ", " + this.Factor ;
    }

}

Ty, and I setted the DataContext in the .xaml.cs
Would it also work with a List ?

Upvotes: 1

Views: 5448

Answers (1)

DotNetRussell
DotNetRussell

Reputation: 9857

You can only bind to properties. Try making your list an

public ObservableCollection<KeyValuePair> IngList { get; private set; }

I also don't see you setting the DataContext so here's an example of that also if that sounds new.

   <Control>
    <Control.Resources>
        <ViewmodelNamespace:ViewModelAddRecipeWindow x:Key="ReceipieViewModel"/>
    </Control.Resources>

    <Grid DataContext="{StaticResource ReceipieViewModel}">
        <ListView ItemsSource="{Binding IngList}"/>
    </Grid>
  </Control>

Here is a Tutorial on binding to a list in WPF

Upvotes: 1

Related Questions