Satish Nissankala
Satish Nissankala

Reputation: 141

Two way binding not working correctly

I am using WPF MVVM Pattern. I have 2 ListBoxes and a DataGrid in my view. I am using EntityFramework to get data from SQL Server. My ViewModel looks like this

    private Types _type;
    private Users _user;
    private ObjectResult<APP> _dataContext;

    public IEnumerable<Types> Categories
    {
        get;
        private set;
    }

    public IEnumerable<Users> SystemNames
    {
        get;
        private set;
    }

    public Types SelectedType
    {
        get
        {
            return _type;
        }
        set
        {
            _type = value;
            RaisePropertyChanged("SelectedType");
        }
    }       

    public Users SelectedUser
    {
        get
        {
            return _user;
        }
        set
        {
            _user = value;
            RaisePropertyChanged("SelectedUser");
        }
    }

    public ObjectResult<APP> DContext
    {
        get
        {
            return _dataContext;
        }
        set
        {
            _dataContext = value;
            RaisePropertyChanged("DContext");
        }
    }

    public ObjectResult<APP> GetDataContext()
    {
        AppLogEntities context = new AppLogEntities();
        return context.GetAppLog(SelectedUser.User, SelectedType.Type);
    }

    public DetailsViewModel()
    {
        Categories = new List<Types>
        {
            new Types{Type = "All"},
            new Types{Type = "Information"},
            new Types{Type = "Warning"},
            new Types{Type = "Error"}
        };

        SystemNames = new List<Users>
        {
            new Users{User = "All"},
            new Users{User = "SYS_01"},
            new Users{User = "SYS_02"}
        };

        SelectedType = new Types();
        SelectedUser = new Users();

        DContext = GetDataContext();
    }`

And my View liiks like this

<Window x:Class="SingleAppLogMVVM.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:vm="clr-namespace:SingleAppLogMVVM"
    Title="MainWindow" Height="800" Width="1000">
<Window.DataContext >
    <vm:DetailsViewModel />
</Window.DataContext>
<Grid>
    <ListBox Height="200" HorizontalAlignment="Left" Margin="50,50,0,0" Name="fTypeListBox" VerticalAlignment="Top" Width="125" SelectionMode="Single" IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding Categories}" SelectedItem="{Binding SelectedType, Mode=TwoWay}" >
        <ListBox.ItemTemplate >
            <DataTemplate >
                <DockPanel Width="120" LastChildFill="True" >
                    <TextBlock Text="{Binding Type, Mode=TwoWay}" Width="110" Margin="5" />
                </DockPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
    <ListBox Height="Auto" HorizontalAlignment="Left" Margin="50,275,0,50" Name="fUserListBox" VerticalAlignment="Stretch" Width="125" SelectionMode="Single" IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding SystemNames}" SelectedItem="{Binding SelectedUser, Mode=TwoWay}"  >
        <ListBox.ItemTemplate >
            <DataTemplate >
                <DockPanel Width="120" LastChildFill="True" >
                    <TextBlock Text="{Binding User, Mode=TwoWay}" Width="110" Margin="5" />
                </DockPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
    <DataGrid AutoGenerateColumns="False" Height="350" HorizontalAlignment="Stretch" Margin="225,50,50,0" IsReadOnly="True" Width="Auto"
              VerticalAlignment="Top" CanUserReorderColumns="False" CanUserResizeColumns="False" Name="fDGrid"  VirtualizingStackPanel.IsVirtualizing="True"
              CanUserResizeRows="False" IsManipulationEnabled="True" RowHeight="35" SelectionMode="Single" VirtualizingStackPanel.VirtualizationMode="Recycling"
              ItemsSource="{Binding DContext, Mode=OneWay}">
        <DataGrid.Columns>
            <DataGridTextColumn Header="ID" Binding="{Binding Path=ID}" Width="5*" />
            <DataGridTextColumn Header="IID" Binding="{Binding Path=IID}" Width="5*" />
            <DataGridTextColumn Header="INSTANCEID" Binding="{Binding Path=INSTANCEID}" Width="10*" />
            <DataGridTextColumn Header="TYPE" Binding="{Binding Path=TYPE}" Width="10*" />
            <DataGridTextColumn Header="SOURCE" Binding="{Binding Path=SOURCE}" Width="10*" />
            <DataGridTextColumn Header="TIME" Binding="{Binding Path=TIME}" Width="10*" />
            <DataGridTextColumn Header="SNAME" Binding="{Binding Path=SNAME}" Width="10*" />
            <DataGridTextColumn Header="MESSAGE" Binding="{Binding Path=MESSAGE}" Width="15*" />
            <DataGridTextColumn Header="ACTIONS" Binding="{Binding Path=ACTIONS}" Width="15*" />
            <DataGridTextColumn Header="CLEARED ON" Binding="{Binding Path=CLEAREDON}" Width="10*" />
        </DataGrid.Columns>
    </DataGrid>        
</Grid>

I am able to get my LisBoxes populated. And also I am able to get my DataGrid populated if a plugin values manually in my ViewModel code

 public ObjectResult<APP> GetDataContext()
    {
        AppLogEntities context = new AppLogEntities();
        return context.GetAppLog(SelectedUser.User, SelectedType.Type);
    }

I don't understand why it isn't working based on my selection from ListBoxes. Please help me out.

Upvotes: 0

Views: 887

Answers (2)

Anton
Anton

Reputation: 7719

a couple small changes are required to get the results you are after

public Types SelectedType
{
    get
    {
        return _type;
    }
    set
    {
        _type = value;
        RaisePropertyChanged("SelectedType");
        DContext = GetDataContext(); //refresh the data
    }
}       

public Users SelectedUser
{
    get
    {
        return _user;
    }
    set
    {
        _user = value;
        RaisePropertyChanged("SelectedUser");
        DContext = GetDataContext(); //refresh the data
    }
}


public DetailsViewModel()
{
    Categories = new List<Types>
    {
        new Types{Type = "All"},
        new Types{Type = "Information"},
        new Types{Type = "Warning"},
        new Types{Type = "Error"}
    };

    SystemNames = new List<Users>
    {
        new Users{User = "All"},
        new Users{User = "SYS_01"},
        new Users{User = "SYS_02"}
    };

    _type = new Types();  //use the field rather than the property so GetDatacontenxt doesnt get called multiple times
    _user = new Users();
    DContext = GetDataContext();
}

Upvotes: 1

saus
saus

Reputation: 2174

you will need to manually call GetDataContext() every time your SelectedUser and SelectedType properties are changed in the viewmodel. The property setters are a good way to do this - although if GetDataContext() is a long running operation then you should do it asynchronously so the UI doesn't freeze while the results are loading.

Upvotes: 1

Related Questions