Amjad Sham
Amjad Sham

Reputation: 21

WPF Listview binding userControl property

I'm new at WPF. I have Listview, and i want to display more than usercontrol at it.

I used ItemTemplate.

Listview like this:

    <ListView HorizontalAlignment="Stretch" Margin="0,40,0,0" Name="listView1" VerticalAlignment="Stretch"
              ItemTemplate="{StaticResource DriveUserControlDataTemplate}" >
        <ListView.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel Width="{Binding (FrameworkElement.ActualWidth), RelativeSource={RelativeSource AncestorType=ScrollContentPresenter}}"
                               ItemWidth="{Binding (ListView.View).ItemWidth, RelativeSource={RelativeSource AncestorType=ListView}}"
                               MinWidth="{Binding ItemWidth, RelativeSource={RelativeSource Self}}"
                               ItemHeight="{Binding (ListView.View).ItemHeight, RelativeSource={RelativeSource AncestorType=ListView}}" />
            </ItemsPanelTemplate>
        </ListView.ItemsPanel>
    </ListView>


    <DataTemplate x:Key="DriveUserControlDataTemplate" >
        <StackPanel Margin="10">
            <c:DriveUserControl Drive="{Binding Name}" EventAdd="DriveUserControlAdd_Click">
            </c:DriveUserControl >
        </StackPanel>
    </DataTemplate>

and i want to bind usercontrols by this code:

 listView1.ItemsSource = DriveInfo.GetDrives()
                .Where(item => item.IsReady && item.DriveType == DriveType.Removable)
                .ToList();

Class DriveInfo has property named Name

Any one tell me why it didn't bind?

Upvotes: 0

Views: 2238

Answers (1)

sepai
sepai

Reputation: 166

The main method of implementation for WPF is MVVM (Model View ViewModel) and not code behind. What you need to do is implement the MVVM development pattern. Can I suggest you start off by reading one of the many online articles about MVVM, http://msdn.microsoft.com/en-us/magazine/dd419663.aspx

However instead of just pointing you to a link I will endeavour to attempt to answer your question, as best I can.

Create a class and call it MainWindowViewModel and implement the INotifyPropertyChanged interface. Once you've done this implement the PropertyChanged event. At this point i like to cheat and write myself a helper method to raise this event for me when my properties change.

public class MainWindowViewModel : INotifyPropertyChanged {
  public event PropertyChangedEventHandler PropertyChanged;

  private void raisePropertyChanged(string propertyName) {
    if (PropertyChanged != null) PropretyChanged(this, new PropertyChangedEventArgs(propertyName));
  }
}

So at this point you should have something as illustrated above. This is the ViewModel.

The next step is to create the properties that you want to expose to the user interface, the View. In your case you want to list the drives available on your computer. So we need to create an ObservableCollection of string values, as follows.

private ObservableCollection<string> _drives = new ObservableCollection<string>();
public ObservableCollection<string> Drives {
  get { return _drives; }
  set {
    _drives = value;
    this.raisePropertyChanged("Drives");
  }
}

OK with me so far? So now we have a view model and an empty list of string values. AWESOME HUH? Next step is to populate your list of strings "Drives" so we write a simple Init method in the class.

public void Init() {
  this.Drives = new ObservableCollection<string>(DriveInfo.GetDrives()
                .Where(item => item.IsReady && item.DriveType == DriveType.Removable)
                .ToList());
}

Lets leave the code alone for the moment and now we turn our attention to the View (your UI). In your UI you need to define the namespace where your ViewModel class resides. This is put into the first element of xaml in your window.

xmlns:vms="clr-namespace:applicationNameSpace;assembly=applicationAssemblyName"

Don't forget to substitute the applicationNameSpace and applicationAssemblyName for the correct values.

Next we declare the ViewModel class in the resources of your window.

<Window.Resources>
  <vms:MainWindowViewModel x:Key="mainWindowVms"/>
</Window.Resources>

Last but not least create a Loaded event for your window and in the code behind, yes I said code behind, put the following code.

MainWindowViewModel mainWindowVms = Resources["mainWindowVms"] as MainWindowViewModel;
mainWindowVms.Init();

So this only leaves one last thing to do, which is answer your question about "Why it didn't bind?" Well because the ItemsSource is a property that needs to be bound to by a property from a ViewModel. In otherwords it uses the INotifyPropertyChanged interface to notify the UI thread that a change has been made to the object that it is bound to. Binding in code behind kind of defeats the purpose of WPF. So in order to get the binding going you simply specify the binding in your xaml.

<ListView ItemsSource="{Binding Source={StaticResource mainWindowVms}, Path=Drives"/>

This way you have your view model worry about the state and population of your list and your UI just does what it's told.

So there you have it. It is important, especially if you're new to WPF that you read up on MVVM pattern development because once you start it is really hard to stop and you'll wonder what you ever did before it.

Upvotes: 1

Related Questions