2

I am new-bee at WPF, i am trying to populate my combox control which is there within my listbox

XAML :

        <Window.Resources>
    <DataTemplate x:Key="UserTemplate" >
      <StackPanel Orientation="Horizontal" >
        <ComboBox Name="rule" ItemsSource="{Binding}" DisplayMemberPath="DataContext.RuleType"  Width="85" Height="20"
          SelectedValuePath="DataContext.RuleType" SelectedValue="{Binding Path=DataContext.RuleType}"/>
        <TextBlock Text="{Binding Path= Name1}" Width="85" Margin="5,5,5,5"></TextBlock>
        <Button Content="Delete" Click="cmdDeleteUser_Clicked" Margin="5,5,5,5" />
        <Button Content="Add" Click="cmdAddUser_Clicked" Margin="5,5,5,5" />
      </StackPanel>
    </DataTemplate>

  </Window.Resources>

  <Grid>
    <ListBox Name="lbUsers" ItemsSource="{Binding }" ItemTemplate="{StaticResource UserTemplate}"/>
  </Grid> 

CODE BEHIND:

        public ObservableCollection<User> Users;
        ObservableCollection<Listdata> listeddata;
        ObservableCollection<Records> Record;


        public MainWindow()
        {
            InitializeComponent();
            Users = new ObservableCollection<User>() {
                    new User() { Name = "", Age = "" },
                 };

            DataboundListbox.Records record = new Records();
            RuleType = record.record_Rule();
            lbUsers.DataContext = Users;

        }
        private string _Name;
        public string Name1
        {
            get { return _Name; }
            set
            {
                if (value != _Name)
                {
                    _Name = "John";
                    NotifyPropertyChanged("Name");
                }
            }
        }
        private List<string> _RuleType;
        public List<string> RuleType
        {
            get { return _RuleType; }
            set
            {
                if (value != _RuleType)
                {
                    _RuleType = value;
                    NotifyPropertyChanged("RuleType");
                }
            }
        }

        private void NotifyPropertyChanged(string info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }

        private void cmdDeleteUser_Clicked(object sender, RoutedEventArgs e)
        {
            Button cmd = (Button)sender;
            if (cmd.DataContext is User)
            {
                User deleteme = (User)cmd.DataContext;
                Users.Remove(deleteme);
            }
        }
        private void cmdAddUser_Clicked(object sender, RoutedEventArgs e)
        {
            Button cmd = (Button)sender;
            if (cmd.DataContext is User)
            {
                var addedUser = new User() { Name = "", Age = "" };
            Users.Add(addedUser);
            }
        }


        private List<string> _prp;
        public List<string> prp
        {
            get { return _prp; }
            set
            {
                if (value != _prp)
                {
                    _RuleType = value;
                    NotifyPropertyChanged("prp");
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged; 
4
  • I am also new to xaml, specially the binding stuff, but I found this guide pretty easy and straightforward. Perhaps you can check your code against it. msdn.microsoft.com/en-us/library/windows/apps/xaml/… Commented Jul 15, 2015 at 8:31
  • What are the expected ItemSource for your ListView and Combobox? It seems like your binding is not correct. Commented Jul 15, 2015 at 8:36
  • You should use ObservableCollection instead of lists. Commented Jul 15, 2015 at 9:04
  • So, what errors are you getting or what is the problem? Commented Jul 15, 2015 at 9:09

2 Answers 2

1

Before I can answer your question there are some confusions that should be cleared up.

  1. If User has already a member named Name then what's Name1 in parent class for?

  2. If RuleType is a list, how come it's set as the SelectedValue of your ComboBox, Shouldn't it be ComboBox.itemsSource instead? If it should, then where is the property defined to keep the ComboBox.SelectedValue?

  3. How come there is an Add button inside the UserTemplate? Delete button is ok but i think Add belongs outside of the ListBox.

If i understand your issue correctly, then this is the solution I can think of.

Fisrt: User needs a property like SelectedRule to keep Combobox.SelectedItem:

public class User : INotifyPropertyChanged
{

    // implementation of INotifyPropertyChanged

    string _name;
    public string Name
    {
        get
        {
            return _name;
        }
        set
        {
            _name = value;
            NotifyPropertyChanged("Name");
        }
    }

    int _age;
    public int Age
    {
        get
        {
            return _age;
        }
        set
        {
            _age = value;
            NotifyPropertyChanged("Age");
        }
    }

    string _selectedRule;
    public string SelectedRule
    {
        get
        {
            return _selectedRule;
        }
        set
        {
            _selectedRule = value;
            NotifyPropertyChanged("SelectedRule");
        }
    }
}

Second: Your DataTemplate should change like this:

<Window.Resources>
    <DataTemplate x:Key="UserTemplate" >
        <StackPanel Orientation="Horizontal" >
            <ComboBox Name="rule" ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=RuleType}" DisplayMemberPath="."  Width="85" Height="20"
      SelectedItem="{Binding SelectedRule}"/>
            <TextBlock Text="{Binding Path= Name}" Width="85" Margin="5,5,5,5"></TextBlock>
            <Button Content="Delete" Click="cmdDeleteUser_Clicked" Margin="5,5,5,5" />
        </StackPanel>
    </DataTemplate>
</Window.Resources>

Finally the ListBox part changes as below:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <ListBox Grid.Row="0" Name="lbUsers" ItemsSource="{Binding}" ItemTemplate="{StaticResource UserTemplate}"/>
    <Button Grid.Row="1" Content="Add" Click="cmdAddUser_Clicked" Margin="5,5,5,5" />
</Grid>

If you're gonna bring Add button out like the above code, then you should remove if (cmd.DataContext is User) from cmdAddUser_Clicked method.

Sign up to request clarification or add additional context in comments.

1 Comment

Hi bahman_aries, thanks for the corrections it helped a lot. 1.name1 was another property which i created while fixing the bug, so it just got copy pasted 2. I had set the datacontext in codebehind, the rest of the xaml code was trial and error so while pasting it , i dint removed it.. my bad 3.Add and Delete buttons both needs to be there within the data template. Thanks again !!!
1

Problem :

The main problem is on this two line:

   {Binding Path=DataContext.RuleType}
   {Binding Path= Name1}
  1. Since you already declare your dataContext, DataContext.RuleType will causes the compiler to search for yourdatacontext.DataContext.RuleType which is obviously not the thing you want.

    lbUsers.DataContext = Users;
    
  2. Your data context is a collection of User class and does not contain Name1. Thus Binding Path=Name1 will return "property not found" error

Solution

In WPF, MVVM ( model view viewmodel) pattern is highly encouraged. One of its main feature is it seperate GUI logic from Business Logic, making the code cleaner and easier to maintain.

Step 1: Create a ViewModel

  public class UserViewModel:INotifyPropertyChanged
 {
    private string name;
    private string age;
    private string rule;
    private List<string> ruleType;

    public String Name 
    {
        get { return name; }
        set { name = value; NotifyPropertyChanged("Name"); }
    }

    public String Age
    {
        get { return age; }
        set { age = value; NotifyPropertyChanged("Age"); }
    }

    public String Rule 
    {
        get { return rule; }
        set { rule = value; NotifyPropertyChanged("Rule"); }
    }
    public List<string> RuleType
    {
        get { return ruleType; }
        set { ruleType = value; NotifyPropertyChanged("RuleType"); }
    }

    public UserViewModel() 
    {
        name = "name";
        age = "";
        ruleType = new List<string>();
    }

    #region NotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;
    protected void NotifyPropertyChanged(String info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }
    #endregion
 }

}

Step 2 : Link your data context to the viewmodel

    public MainWindow()
    {
        InitializeComponent();
        Users = new ObservableCollection<UserViewModel>();
        //setup your data here
        //example:

        UserViewModel userViewModel = new UserViewModel();
        //populate your combobox here
        userViewModel.RuleType.Add("rule1")
        userViewModel.RuleType.Add("rule2");
        userViewModel.RuleType.Add("rule3");
        Users.Add(new UserViewModel());

        lbUsers.DataContext = Users ;

    }

Step 3 : Update your xaml

 <Window.Resources>
        <DataTemplate x:Key="UserTemplate" >
            <StackPanel Orientation="Horizontal" >
                <ComboBox Name="rule" ItemsSource="{Binding RuleType}"  Width="85" Height="20"
       SelectedValue="{Binding Rule}"/>
                <TextBlock Text="{Binding Path= Name}" Width="85" Margin="5,5,5,5"></TextBlock>
                <Button Content="Delete" Click="cmdDeleteUser_Clicked" Margin="5,5,5,5" />
                <Button Content="Add" Click="cmdAddUser_Clicked" Margin="5,5,5,5" />
            </StackPanel>
        </DataTemplate>

    </Window.Resources>

When i am typing, bahman already post a quite detailed answer.So i stopped here. If you require any explaination or solution from me just asked will do.

In future if you suspect any error regarding binding, you can search your output window. If you see your output window you possibly will found this

System.Windows.Data Error: 40 : BindingExpression path error: 'DataContext' property not found on 'object' ''User' (HashCode=9080996)'. BindingExpression:Path=DataContext.RuleType; DataItem='User' (HashCode=9080996); target element is 'ComboBox' (Name=''); target property is 'SelectedValue' (type 'Object')
System.Windows.Data Error: 40 : BindingExpression path error: 'Name1' property not found on 'object' ''User' (HashCode=9080996)'. BindingExpression:Path=Name1; DataItem='User' (HashCode=9080996); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.