Jatinder Walia
Jatinder Walia

Reputation: 141

wpf ListItem SelectedValue Object is always null

I have a simple ListBox and a TextBox as under.I want to display the selectedvalue property of Listbox in the textbox,but my ViewModel's selected object is always null. What am i missing here?

My XAML

<StackPanel>
    <Canvas>
        <TextBox x:Name="TxtMail" Width="244" FontSize="14" Canvas.Left="36" Canvas.Top="34" Height="20" Text="{Binding CurrentRec.Name,Mode=OneWay}" />
        <ListBox x:Name="AllMatching" Width="{Binding ElementName=TxtMail,Path=Width}" Height="100" Canvas.Top="54" Canvas.Left="36"  DisplayMemberPath="Name" SelectedItem="{Binding CurrentRec,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" SelectedValue="Name" SelectedValuePath="Name" ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.HorizontalScrollBarVisibility="Auto" />
        <Button Content="Test" x:Name="cmdtest" Click="cmdtest_Click"/>
    </Canvas>

My ViewModel:

public class VM_Data : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    public int p_ID;
    public double p_SP, p_CP;
    public string p_Name;
    public List<DM_Data> AllData;

    public DM_Data CurrentRec;
    public VM_Data()
    {
        LoadData();
    }
    public int ID
    {
        get { return p_ID; }
        set
        {
            if (p_ID != value)
            {
                RaisePropertyChangedEvent("ID");
                p_ID = value;
            }
        }
    }

    public double SP
    {

        get { return p_SP; }
        set
        {
            if (p_SP != value)
            {
                RaisePropertyChangedEvent("SP");
                p_SP = value;
            }
        }
    }
    public double CP
    {
        get { return p_CP; }
        set
        {
            if (p_CP != value)
            {
                RaisePropertyChangedEvent("CP");
                p_CP = value;
            }
        }
    }

    public string Name
    {
        get { return p_Name; }
        set
        {
            if (p_Name != value)
            {
                RaisePropertyChangedEvent("Name");
                p_Name = value;
            }
        }
    }
    private void LoadData()
    {
        AllData = new List<DM_Data>();
        string[] strNames = "Jatinder;Shashvat;shashikala;shamsher;shahid;justin;jatin;jolly;ajay;ahan;vijay;suresh;namita;nisha;negar;zenith;zan;zen;zutshi;harish;hercules;harman;ramesh;shashank;mandeep;aman;amandeep;amarjit;asim;akshay;amol;ritesh;ritivik;riz;samana;samaira;bhagwandass;bhagwan;bhawna;bhavna".Split(';');
        for(int i=0;i<=strNames.GetUpperBound(0);i++)
        {
            DM_Data NewRec = new DM_Data();
            NewRec.CP = new Random().Next(200, 400);
            NewRec.SP = new Random().Next(1, 10);
            NewRec.ID = i + 1;
            NewRec.Name = strNames[i];
            AllData.Add(NewRec);
        }
        AllData = AllData.OrderBy(item => item.Name).ToList();
    }
    private void RaisePropertyChangedEvent(string Property)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(Property));
        }
    }
}

My DataModel

public class DM_Data
{
    public int p_ID;
    public double p_SP, p_CP;
    public string p_Name;

    public int ID
    {
        get { return p_ID; }
        set { p_ID = value; }
    }

    public double SP
    {
        get { return p_SP; }
        set { p_SP = value; }
    }
    public double CP
    {
        get { return p_CP; }
        set { p_CP = value; }
    }

    public string Name
    {
        get { return p_Name; }
        set { p_Name = value; }
    }

MainWindow.Xaml.cs

public partial class MainWindow : Window
{
    VM_Data ViewModel;
    public MainWindow()
    {
        InitializeComponent();
         ViewModel = new VM_Data();
        this.DataContext = ViewModel;
        AllMatching.ItemsSource = ViewModel.AllData;
    }

    private void cmdtest_Click(object sender, RoutedEventArgs e)
    {
        DM_Data crec = ViewModel.CurrentRec;
    }
}

Upvotes: 0

Views: 108

Answers (3)

mm8
mm8

Reputation: 169390

CurrentRec must be a property that raises the PropertyChanged event:

private DM_Data _currentRec;
public DM_Data CurrentRec
{
    get { return _currentRec; }
    set { _currentRec = value; RaisePropertyChangedEvent("CurrentRec"); }
}

In the code you have posted, it is a field and you cannot bind to fields:

public DM_Data CurrentRec;

Upvotes: 1

Peter
Peter

Reputation: 1687

What you are doing is kind of MVVM, but not really.

Here is a quick fix anyway:

Please take a look at the Bindings.

    <StackPanel>
        <Canvas>
            <TextBox x:Name="TxtMail" Width="244" FontSize="14" Canvas.Left="36" Canvas.Top="34" Height="20" Text="{Binding ElementName=AllMatching, Path=SelectedItem.Name}" />
            <ListBox x:Name="AllMatching" 
                     Width="{Binding ElementName=TxtMail,Path=Width}" 
                     Height="100" 
                     Canvas.Top="54" 
                     Canvas.Left="36"  
                     DisplayMemberPath="Name" 
                     SelectedItem="{Binding CurrentRec,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                     ScrollViewer.VerticalScrollBarVisibility="Auto" 
                     ScrollViewer.HorizontalScrollBarVisibility="Auto" />
            <Button Content="Test" x:Name="cmdtest" Click="cmdtest_Click"/>
        </Canvas>
    </StackPanel>

I think you get the idea at: Text="{Binding ElementName=AllMatching, Path=SelectedItem.Name}".

Aditional Information

First: You fire to early dude. Please first assign the value and then say its changed.

       if (p_Name != value)
        {
            RaisePropertyChangedEvent("Name");
            p_Name = value;
        }

Second: Use a ObservableCollection<DM_Data> to let your ListBox know about changes.

Third: Use the posibility of Binding

Remove AllMatching.ItemsSource = ViewModel.AllData; and go like

        <ListBox x:Name="AllMatching"
                 ItemsSource="{Binding Path=AllData}"
                 ...
                 />

And after all of this - please man check out some tutorials. And also refactor your code from VM_Data to DataViewModel thank you sir.

Upvotes: 0

Maxim
Maxim

Reputation: 2150

You can't bind to fields! CurrentRec must be a property. At now it is a field.

  1. Why do you set ItemsSource in code-behind? Set it in XAML.
  2. You should call RaisePropertyChangedEvent after you've changed backing field, not before.
  3. It is not right pattern for events raising: if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(Property)); } You need to save event delegate to variable first or use ?.Invoke.

  4. Don't create new instances of Random on every iteration of loop because you will get equal values. Create the only one outside of the loop and use it.

Upvotes: 0

Related Questions