Click here to Skip to main content
15,879,072 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I have two UserControls in my MainWindow and UserControl2 has 2 Listboxes,Texboxes and Buttons.When i write some text in TextBox and press Button it should add into the ListBox.Can somebody help me with the code,i'm new to WPF and MVVM

This is my XAML code
<Window x:Class="Wpf_MVVM.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:Wpf_MVVM" 
    Title="title" removed="SlateGray" Height="420" Width="550">


<Grid>
    <local:UserControl1 HorizontalAlignment="Left" VerticalAlignment="Top"/>
    <local:UserControl2 HorizontalAlignment="Left" VerticalAlignment="Top" Margin="150,29,0,0"/>




</Grid>


This is my UserControl1.Xaml code
<UserControl x:Class="Wpf_MVVM.UserControl1"
         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" 
         mc:Ignorable="d" 
         Height="Auto" Width="Auto">
<Grid>
    <ListBox HorizontalAlignment="Left" Height="310" VerticalAlignment="Top" Width="150" Margin="0,40,0,0">
        <ListBoxItem>Name 1</ListBoxItem>
        <ListBoxItem>Name 2</ListBoxItem>
        <ListBoxItem>Name 3</ListBoxItem>
        <ListBoxItem>Name 4</ListBoxItem>
        <ListBoxItem>Name 5</ListBoxItem>
        <ListBoxItem>Name 6</ListBoxItem>
    </ListBox>
    <Label Content="Conversations" HorizontalAlignment="Left" VerticalAlignment="Top"  Height="40" Width="150" FontSize="20" Background="SkyBlue"/>
    <Button Content="Create New Chat" Height="30" HorizontalAlignment="Left" Margin="0,350,0,0" VerticalAlignment="Top" Width="150"/>

</Grid>

This is my UserControl2.Xaml code
<UserControl x:Class="Wpf_MVVM.UserControl2"
         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" 
         mc:Ignorable="d" 
         Height="Auto" Width="390">
<Grid>
    <ListBox Name="listbox1" HorizontalAlignment="Left" Height="310" VerticalAlignment="Top" Width="180" Margin="10,0,0,0"/>
    <ListBox Name="listbox2"  HorizontalAlignment="Left" Height="310" Margin="200,0,0,0" VerticalAlignment="Top" Width="180"/>
    <TextBox Name="tb1" HorizontalAlignment="Left" Height="40" Margin="200,310,0,0" TextWrapping="NoWrap" Text="" VerticalAlignment="Top" Width="130"/>
    <TextBox Name="tb2" Height="40" TextWrapping="NoWrap" Text="" Margin="10,310,245,0"/>
    <Button Command="{Binding ButtonCommand}" Name="btn1" Content="Send" Height="40" HorizontalAlignment="Left" Margin="330,310,0,0" VerticalAlignment="Top" Width="50" />
    <Button Command="{Binding SendControlCommand}" Name="btn2" Content="Send" Height="40" Margin="145,310,200,0"/>

</Grid>
Posted
Updated 9-Aug-22 21:08pm
v2

There is a big difference if you want to use the same ViewModel for both controls or if you want the ViewModel of UserControl1 to be different from UserControl2;s ViewModel, as that would require you have your ViewModels communicate with each other.

If we assume the simpler case (both controls share a single ViewModel) then your implementation is on the right track.

Just make your ListBoxes bind to an item source on the ViewModel, and add to that source when the Button is clicked. It might be convenient for you to use an ObservableCollection as the container for the item source.

A cut-down example might look something like this;

UserControl1.xaml
<usercontrol x:class="WpfMvvm.UserControl1" xmlns:x="#unknown">
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             Background="CornflowerBlue" Padding="10">
    <grid>
        <grid.rowdefinitions>
            <rowdefinition height="Auto" />
            <rowdefinition height="*" />
            <rowdefinition height="Auto" />
        </grid.rowdefinitions>
        <label grid.row="0" content="This list is based on items from UserControl2" />
        <listbox grid.row="1" itemssource="{Binding Path=Items, Mode=OneWay}" />
        <button grid.row="2" content="Clear" command="{Binding Path=ClearCommand, Mode=OneWay}" />
    </grid>
</usercontrol>


UserControl2.xaml
<usercontrol x:class="WpfMvvm.UserControl2" xmlns:x="#unknown">
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             Background="DarkSalmon" Padding="10">
    <stackpanel>
        <label content="Enter string:" />
        <textbox text="{Binding Path=Text, Mode=TwoWay}" />
        <button content="Add" command="{Binding Path=AddCommand, Mode=OneWay}" />
    </stackpanel>
</usercontrol>


ViewModel.cs
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows.Input;

namespace WpfMvvm {
    public class ViewModel : INotifyPropertyChanged {

        public event PropertyChangedEventHandler PropertyChanged;

        private readonly ObservableCollection<string> items = new ObservableCollection<string>();
        private string text;

        private readonly ICommand clearCommand;
        private readonly ICommand addCommand;

        public ViewModel() {
            clearCommand = new Command(items.Clear);
            addCommand = new Command(() => items.Add(Text));
        }

        private void Notify(string propertyName) {
            var handler = PropertyChanged;
            if (handler != null)
                handler(this, new PropertyChangedEventArgs(propertyName));
        }

        public IEnumerable<string> Items {
            get { return items; }
        }

        public ICommand ClearCommand {
            get { return clearCommand; }
        }

        public ICommand AddCommand {
            get { return addCommand; }
        }

        public string Text {
            get { return text; }
            set {
                if (text == value)
                    return;

                text = value;
                Notify("Text");
            }
        }
    }
}
</string></string></string>


MainWindow.xaml
<window x:class="WpfMvvm.MainWindow" xmlns:x="#unknown">
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:l="clr-namespace:WpfMvvm"
        Title="MainWindow" Height="350" Width="525">
    <grid>
        <grid.rowdefinitions>
            <rowdefinition height="*" />
            <rowdefinition height="Auto" />
        </grid.rowdefinitions>
        <l:usercontrol1 grid.row="0" xmlns:l="#unknown" />
        <l:usercontrol2 grid.row="1" xmlns:l="#unknown" />
    </grid>
</window>


MainWindow.xaml.cs
namespace WpfMvvm {
    public partial class MainWindow {
        public MainWindow() {
            InitializeComponent();
            DataContext = new ViewModel();
        }
    }
}


Hope this helps,
Fredrik
 
Share this answer
 
Comments
Fredrik Bornander 29-Oct-13 5:42am    
I left that out deliberately, but it would like something like this;

using System;
using System.Windows.Input;

namespace WpfMvvm {
public class Command : ICommand {
private readonly Action action;

public Command(Action action) {
this.action = action;
}

public bool CanExecute(object parameter) {
return true;
}

public event EventHandler CanExecuteChanged;

public void Execute(object parameter) {
action();
}
}
}
Fredrik Bornander 29-Oct-13 7:34am    
It's because my command implementation assumes a command that can always be invoked.
You're supposed to fire that event when the CanExecute of the command changes, but since this is always true it's irrelevant in this implementation.

Google WPF RelayCommand for a more complete implementation of ICommand.
You should first implement the INotifyPropertyChanged as follows:

C#
public event PropertyChangedEventHandler PropertyChanged;
        public void NotifyPropertyChanged(string propertyname)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyname));
            }
        }



Define a property like this:

C#
private string _contentToAdd;

C#
public string ContentToAdd
{
   get { return this._contentToAdd; }
   set { this._contentToAdd = value; NotifyPropertyChanged("ContentToAdd"); }
}


In XAML, you can bind the textbox input to this property:

XML
<textbox name="tb1" text="{Binding ContentToAdd}" />


And don't forget to set the data context of the view, otherwise, the binding won't work.

Last thing to do is to create a collection where you can add each entry you made in your text box and set the item source of your list box to the collection.

This should work...if you have any further questions, just ask.

EDIT:

Sure:
First, use this namespace:
C#
using System.Collections.ObjectModel;


Then, define property for the collection:

C#
private ObservableCollection<string> _yourList;
public ObservableCollection<string> YourList
{
   get{return this._yourList;}
   set{this._yourList = value; NotifyPropertyChanged;}
}


Don't forget to instantiate the collection in your constructor:

C#
_yourList = new ObservableCollection<string>();



In your add command, add the string to this collection:

C#
yourList.Add(ContentToAdd);


In XAML:

XML
<ListBox ItemsSource ="{Binding YourList}"/>


EDIT v2:


Create new class:

C#
class DelegateCommand : ICommand
    {
        private readonly Predicate<object> _canExecute;
        private readonly Action<object> _execute;

        public event EventHandler CanExecuteChanged;

        public DelegateCommand(Action<object> execute)
        {
            _execute = execute;
        }

        public DelegateCommand(Action<object> execute, Predicate<object> canExecute)
        {
            _execute = execute;
            _canExecute = canExecute;
        }



        public bool CanExecute(object parameter)
        {
            if (_canExecute == null)
            {
                return true;
            }

            return _canExecute(parameter);
        }

        public void Execute(object parameter)
        {
            _execute(parameter);
        }

        public void RaiseCanExecuteChanged()
        {
            if (CanExecuteChanged != null)
            {
                CanExecuteChanged(this, EventArgs.Empty);
            }
        }
    }



In your ViewModel:

C#
public ICommand AddCommand{get;set;}
public void Add(object parameter)
{
   YourList.Add(ContentToAdd);
}


Instantiate your command in your constructor:

C#
AddCommand = new DelegateCommand(Add);


And finally in your XAML:

XML
<Button Command="{Binding AddCommand}"/>


Try this please.
 
Share this answer
 
v3
Comments
Marvin Ma 29-Oct-13 5:15am    
I edited my solution.
Member 10321925 29-Oct-13 5:44am    
@Marvin Actually i needed is when enter my text in the textbox and click on the button then the text should enter into the listbox i have but u didn't write anything for button command can u pls check again
Marvin Ma 29-Oct-13 6:09am    
The text you enter in your text box is bound to your property, which you have to add to your collection because your list box needs an item source.

There are two possibilities for the add functionality for the button:
1) use a routed event
2) use a delegate command

I would prefer the second option because if you're using MVVM this would be the right way because you shouldn't have any code behind in your view.

Are you familiar with delegate commands?
Member 10321925 29-Oct-13 6:15am    
nope, i need to this using commands and i never used commands that's the problem for me
Marvin Ma 29-Oct-13 6:26am    
Edited my solution.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900