xamllistviewbindinguser-controlsdata-objects

Use XAML UserControl with dataobject as property , as DataTemplate in Gridview - Binding


I have a collection of Objects with dependencyproperties, and Observer patern as I feed realtime data in "AssetIHM" Object.

 public class assetVM: DependencyObject ,IObserver
{


    public assetVM(AssetIHM aihm) 
    {
        ObserverCollectionSingleton.ObserverCollectionInstance.Add(this);
        _aihm = aihm;
    }

    private string _assetname;
    public string assetname
    {
        get { return _assetname; }
        set
        {
            _assetname = value;
            SetValue(assetnameprop, value);
        }
    }
    public static readonly DependencyProperty assetnameprop =
    DependencyProperty.Register("assetnameprop",    typeof(string),typeof(assetVM), new UIPropertyMetadata(""));
    ...

I also have a UserControl, Which should display the information contained in the AssetVM object:

 public partial class AssetPanel : UserControl
{ 
    public assetVM Asset 
    {
        get
        {
            return (assetVM)GetValue(assetProperty);
        }
        set
        {
            SetValue(assetProperty, value);
        }

    }
    public static DependencyProperty assetProperty =    DependencyProperty.Register(
       "Asset", typeof(assetVM), typeof(AssetPanel), new   PropertyMetadata(null, new PropertyChangedCallback(OnCurrentItemChanged)));

    public AssetPanel(assetVM _Asset)
    {
        Asset = _Asset;
        this.DataContext = this;
        InitializeComponent();
        ...
    }

    public AssetPanel( )
    {
        this.DataContext = this;
        InitializeComponent();
        ...
    }
    ...

I my main windows, I have a ListBox,

<Window x:Class="ETRportfolio.MainWindow"        
    DataContext = "{Binding RelativeSource={RelativeSource Self}}"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:UserControls="clr-namespace:ETRportfolio"  
    Title="MainWindow" Height="1200" Width="1425">



<StackPanel HorizontalAlignment="Left" Height="1153" VerticalAlignment="Top" Width="1400" Margin="10,10,-18,0">

    <ListBox  x:Name="Gridview" Height="800"    >
         <ListBox.ItemTemplate>
            <DataTemplate>
                <UserControls:AssetPanel Asset="{Binding}" />
            </DataTemplate>
         </ListBox.ItemTemplate>
    </ListBox>
</StackPanel>

MY problem is that I would like to feed my Usercontrol with the data contained is the collection of AssetVM.

public partial class MainWindow : Window
{

    public static Dispatcher curDispatcher;

    public ObservableCollection<assetVM> Datas
    {
        get
        {
            return (ObservableCollection<assetVM>)curDispatcher.Invoke(
                       System.Windows.Threading.DispatcherPriority.DataBind,
                       (DispatcherOperationCallback)delegate { return GetValue(DataSProperty); },
                       DataSProperty);
        }
        set
        {
            curDispatcher.BeginInvoke(DispatcherPriority.DataBind,
                (SendOrPostCallback)delegate { SetValue(DataSProperty, value); },
                value);
        }
    }

    public readonly DependencyProperty DataSProperty = DependencyProperty.Register("DataS", typeof(ObservableCollection<assetVM>), typeof(MainWindow), new PropertyMetadata(null, new PropertyChangedCallback(OnCurrentItemChanged)));
    public MainWindow()
    {

        this.DataContext = this;
        curDispatcher = this.Dispatcher;
        Datas =new ObservableCollection<assetVM>();


        InitializeComponent();
        Gridview.ItemsSource = Datas; 
        addasset.addbtn.Click += onclik;
    }

When the AssetPanel constructor is created, it doesn't bind with My AssetVM datas. I always pass through the empty constructor.

How Can I do that in XAML?
I guess the problem is there:

ListBox.ItemTemplate>
            <DataTemplate>
                <UserControls:AssetPanel Asset="{Binding}" />
            </DataTemplate>
         </ListBox.ItemTemplate>

Thks!

Edit::

I removed this.DataContext = this;

In the UserControl constructor, but the UserControl Constructor called when a DataObject

assetVM

is added to the ObservableCollection Datas, used as datasource for the Listview, is this the empty constructor. but not:

 public AssetPanel(assetVM _Asset)
>     {
>         Asset = _Asset; 
>         InitializeComponent();
>         ValuationInfo.ItemsSource = new List<string> { "%", "Value" };
>         AVbox.ItemsSource = Enum.GetValues(typeof(AV)).Cast<AV>();
>     }

So it doesn't bind.

Edit2::

 private static void OnCurrentItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {

            AssetPanel instance = (AssetPanel)d;
            instance.Asset = (assetVM)e.NewValue;
            return;
        }

It binds ! :)

Nevertheless, the Registered Dependency properties in the dataobject are not displayed.

This is my Assetpanel xaml:

<UserControl x:Class="ETRportfolio.AssetPanel" 
             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" 
             d:DesignHeight="152" d:DesignWidth="1400">
    <Grid  >
        <Grid.RowDefinitions>
            <RowDefinition Height="30"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Border BorderBrush="#FFDE6A6A" BorderThickness="1" Grid.Row="0" Grid.Column="0" Background="lightblue">
            <TextBlock x:Name="assetnamebox" TextWrapping="Wrap" Text="{Binding RelativeSource={RelativeSource AncestorType=UserControl }, Path = assetnameprop, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"  HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="15"/>
        </Border>
   ...

TextBlock x:Name="assetnamebox" TextWrapping="Wrap" Text="{Binding RelativeSource={RelativeSource AncestorType=UserControl }, Path = assetnameprop,

is not binding with assetVM.assetname VIA the DependencyProperty assetnameprop.

What is wrong there?

thks


Solution

  • Setting a UserControl's DataContext to itself, as done in your constructors by the statements

    this.DataContext = this;
    

    effectivly disables binding to properties of inherited DataContexts, like in

    <ListBox.ItemTemplate>
        <DataTemplate>
            <UserControls:AssetPanel Asset="{Binding}" />
        </DataTemplate>
    </ListBox.ItemTemplate>
    

    where the binding source is the inherited DataContext of the ListBoxItems, i.e. an assetVM instance.

    Remove the DataContext assignment from your UserContr's constructors.