WPF Changing Datacontexts and Views in the Same Window

I am new to WPF am and is porting my application from VC ++ 6.0 / MFC to C # / WPF (VS2013). Most of my windows development has been in VC ++ / MFC. I'm trying to stick with the MVVM pattern and writing some proof-of-concept applications to keep my feet wet. So far, I have one point.

When my application starts up, it will present a tree view of customers and invoices. It works well for me using a simple hierarchical data template with each level binding to my local data type (view model). I want this to happen when the bill is selected (right now I have a button to click on the invoice template). I want the treeview to be replaced with a detailed account view (I don't want the dialog to pop up to the top). Startup Screen

Xaml for this:

   <DockPanel>
    <TreeView x:Name="trvGroups" ItemsSource="{Binding LBGroups}" VirtualizingPanel.IsVirtualizing="True" VirtualizingPanel.VirtualizationMode="Recycling">
    <TreeView.ItemContainerStyle>
        <!--
            This Style binds a TreeViewItem to a LBtreeViewItemViewModel
        -->
        <Style TargetType="{x:Type TreeViewItem}">
            <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
            <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
            <Setter Property="FontWeight" Value="Normal" />
        </Style>
    </TreeView.ItemContainerStyle>

    <TreeView.Resources>
        <HierarchicalDataTemplate
            DataType="{x:Type local:GroupViewModel}"
            ItemsSource="{Binding Children}"
            >
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding GroupName}" />
            </StackPanel>
        </HierarchicalDataTemplate>

        <HierarchicalDataTemplate 
            DataType="{x:Type local:BillViewModel}"
            ItemsSource="{Binding Children}">
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding BillName}" />
                <Button Command="{Binding Path=BillEditCommand}">Edit</Button>
            </StackPanel>
        </HierarchicalDataTemplate>
    </TreeView.Resources>
    </TreeView>
</DockPanel>

      

Now I have more questions than anything. Should I define each view as a custom control and put it in window.resources? Am I using data templates? I guess I would change the data context to point to the detail invoice view model. What's the best way to do this?

My goal is to stick to MVVM as I understand it - to have nothing in the code (or as little as possible).

I'm looking for more pointers to get me started on the right track as I research. I'm a little woozy at the moment.

Thanks in advance.

+3


source to share


1 answer


I will show you a simple basic details scenario where you can select models in your TreeView and Edit Them.

CS:

       public partial class MainWindow : Window , INotifyPropertyChanged
{
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = this;
    }

    private ICommand onEditBillCommand;
    public ICommand OnEditBillCommand
    {
        get
        {
            if (onEditBillCommand == null)
                onEditBillCommand = new RelayCommand<Bill>
                    (
                        bill => { CurrentBill = bill; }
                    );
            return onEditBillCommand;
        }
    }

    private Bill currectBill;
    public Bill CurrentBill
    {
        get { return currectBill; }
        set
        {
            currectBill = value;
            PropertyChanged(this, new PropertyChangedEventArgs("CurrentBill"));
        }
    }

    public List<Customer> Customers
    {
        get
        {
            List<Customer> customers = new List<Customer>();
            for (int i = 0; i < 5; i++)
            {
                customers.Add(CreateMockCustomer(i));
            }
            return customers;
        }
    }

    private Customer CreateMockCustomer(int g )
    {
        Customer c = new Customer();

        c.Name = "John (" + g + ")" ;

        for (int i = 0; i < 3; i++)
        {
            c.Bills.Add(CreateMockBill());
        }

        return c;
    }

    private Bill CreateMockBill()
    {
        Bill b = new Bill();

        b.Price = 55.5;
        b.BoughtOnDate = DateTime.Now.Date;

        return b;
    }

    public event PropertyChangedEventHandler PropertyChanged = delegate { };
}


public class Customer : INotifyPropertyChanged
{
    private string name;
    public string Name
    {
        get { return name; }
        set { name = value; }
    }

    private ObservableCollection<Bill> bills;
    public ObservableCollection<Bill> Bills
    {
        get
        {
            if (bills == null)
            {
                bills = new ObservableCollection<Bill>();
            }
            return bills;
        }
    }


    public event PropertyChangedEventHandler PropertyChanged = delegate { };
}

public class Bill : INotifyPropertyChanged
{
    private double price;
    public double Price
    {
        get { return price; }
        set
        {
            price = value;
            PropertyChanged(this, new PropertyChangedEventArgs("Price"));
        }
    }

    private DateTime boughtOnDate;
    public DateTime BoughtOnDate
    {
        get { return boughtOnDate; }
        set
        {
            boughtOnDate = value;
            PropertyChanged(this, new PropertyChangedEventArgs("BoughtOnDate"));
        }
    }


    public event PropertyChangedEventHandler PropertyChanged = delegate { };
}

public interface IRelayCommand : ICommand
{
    void RaiseCanExecuteChanged();
}
public class RelayCommand<T> : IRelayCommand
{
    private Predicate<T> _canExecute;
    private Action<T> _execute;

    public RelayCommand(Action<T> execute, Predicate<T> canExecute = null)
    {
        _execute = execute;
        _canExecute = canExecute;
    }

    private void Execute(T parameter)
    {
        _execute(parameter);
    }

    private bool CanExecute(T parameter)
    {
        return _canExecute == null ? true : _canExecute(parameter);
    }

    public bool CanExecute(object parameter)
    {
        return parameter == null ? false : CanExecute((T)parameter);
    }

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

    public event EventHandler CanExecuteChanged;

    public void RaiseCanExecuteChanged()
    {
        var temp = Volatile.Read(ref CanExecuteChanged);

        if (temp != null)
            temp(this, new EventArgs());
    }
}

      



XAML:

     <Window>
         <Window.Resources>
           <HierarchicalDataTemplate x:Key="customerTemplate" DataType="{x:Type local:Customer}" ItemsSource="{Binding Bills}">
               <HierarchicalDataTemplate.ItemTemplate>
                  <DataTemplate>
                    <Grid>
                       <Grid.ColumnDefinitions>
                           <ColumnDefinition/>
                           <ColumnDefinition/>
                           <ColumnDefinition/>
                       </Grid.ColumnDefinitions>

                       <TextBlock Text="{Binding Price}" />
                       <TextBlock Text="{Binding BoughtOnDate}" Grid.Column="1" />
                       <Button Content="Edit" Grid.Column="2"
                            Command="{Binding RelativeSource={RelativeSource AncestorType=Window},Path=DataContext.OnEditBillCommand}" 
                            CommandParameter="{Binding}"/> 

                   </Grid>
               </DataTemplate>
           </HierarchicalDataTemplate.ItemTemplate>

           <TextBlock Text="{Binding Name}" FontFamily="Arial" FontSize="16" FontWeight="Bold" />

        </HierarchicalDataTemplate>

   </Window.Resources>

   <Grid>
       <Grid.ColumnDefinitions>
           <ColumnDefinition />
           <ColumnDefinition Width="0.05*"/>
           <ColumnDefinition />
       </Grid.ColumnDefinitions>


       <TreeView ItemsSource="{Binding Customers}" ItemTemplate="{StaticResource customerTemplate}">

       </TreeView>


       <Grid Grid.Column="2" DataContext="{Binding CurrentBill, Mode=OneWay}" Background="AliceBlue">
           <Grid.RowDefinitions>
              <RowDefinition />
              <RowDefinition />
           </Grid.RowDefinitions>

           <TextBox Text="{Binding Price, Mode=TwoWay}"  Margin="50"/>
           <TextBox Text="{Binding BoughtOnDate, Mode=TwoWay}" Grid.Row="1" Margin="50"/>


      </Grid>

   </Grid>     

      

+1


source







All Articles