0

I have 2 user controls in MainWindow.xaml, They are SidePannel and Description. I am passing an DictionaryModel Object. In the DictionaryModel object there is a Collection of Words and Another object called SidePannelModel. In the SidePannelModel there is another collection of Words and a string property.

DictionaryModel

public class DictionaryModel : INotifyPropertyChanged
{

    public event PropertyChangedEventHandler PropertyChanged;

    public SidePannelModel SideModel { get; set; }
    public IEnumerable<WordModel> Language2 { get; set; }

    public void ToggleLanguage()
    {
        var temp = this.Language2;
        this.Language2 = this.SideModel.Language1;
        this.SideModel.Language1 = temp;

        OnPropertyChanged("DictionaryChanged");
    }


    protected void OnPropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }

SidePannelModel

public class SidePannelModel
{
    public IEnumerable<WordModel> Language1 { get; set; }
    public string SearchWord { get; set; }
}

I am passing the DictionaryModel to DataContext in MainWindow.xaml.cs.

    public partial class MainWindow : Window
    {
        private DictionaryModel dictionary;

        public MainWindow()
        {
            InitializeComponent();
            dictionary = new DictionaryModel
            {
                    SideModel = new SidePannelModel {
                    SearchWord=null,
                    Language1 = new List<WordModel>() 
                    { 
                        new WordModel() { Word = "Test1" }
                        , new WordModel() { Word = "Test2" }
                        , new WordModel() { Word = "Test3" }
                        , new WordModel() { Word = "Test4" }
                        , new WordModel() { Word = "Test5" }
                        , new WordModel() { Word = "Test6" }
                        , new WordModel() { Word = "Test7" }
                        , new WordModel() { Word = "Test8" }
                        , new WordModel() { Word = "Test9" }
                        , new WordModel() { Word = "Test10" }

                    } as IEnumerable<WordModel>
                },


                Language2 = new List<WordModel>() 
                { 
                    new WordModel() { Word = "Test1" }
                    , new WordModel() { Word = "Test2" }
                    , new WordModel() { Word = "Test3" }
                    , new WordModel() { Word = "Test4" }
                    , new WordModel() { Word = "Test5" }
                    , new WordModel() { Word = "kkkkk" }
                    , new WordModel() { Word = "Test7" }
                    , new WordModel() { Word = "Test8" }
                    , new WordModel() { Word = "Test9" }
                    , new WordModel() { Word = "Test10" }

                } as IEnumerable<WordModel>,

            };

            this.DataContext = dictionary;
        }
     }

This is how I pass the Collection of Words and the SidePannelModel to the user controllers in the ManiWindow.xaml

<Window x:Class="ThaiDictionary.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:sidePanel="clr-namespace:ThaiDictionary"
    Title="MainWindow"
    Height="619">
<Window.Resources>
    <Style TargetType="{x:Type ToggleButton}"
       x:Key="toggleButtonStyle">
        <Style.Triggers>
            <Trigger Property="IsChecked" Value="True">
                <Setter Property="Content" Value="Thai to English" />
            </Trigger>
            <Trigger Property="IsChecked" Value="False">
                <Setter Property="Content" Value="English to Thai" />
            </Trigger>
        </Style.Triggers>
    </Style>
</Window.Resources>

<Grid Margin="0,0,2,0">

    <DockPanel LastChildFill="True">
        <Menu IsMainMenu="True" DockPanel.Dock="Top">
            <MenuItem Header="_File" />
            <MenuItem Header="_Edit" />
            <MenuItem Header="_View" />
            <MenuItem Header="_Window" />
            <MenuItem Header="_Help" />
        </Menu>
        <StatusBar Height="22" DockPanel.Dock="Bottom"/>
        <sidePanel:SidePanel SideModel="{Binding SidePModel, Mode=TwoWay}" DockPanel.Dock="Left" MinWidth="200" MinHeight="540" Margin="5,5,5,1" Width="196"/>
        <DockPanel LastChildFill="True" DockPanel.Dock="Left">
            <ToggleButton IsChecked="False" DockPanel.Dock="Top"  HorizontalAlignment="Left" Height="30" Width="150" Style="{StaticResource toggleButtonStyle}" Checked="ToggleButton_Checked" Unchecked="ToggleButton_Unchecked">
            </ToggleButton>
            <sidePanel:Description DockPanel.Dock="Top" WordsList2="{Binding Language2, Mode=TwoWay}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
        </DockPanel>

    </DockPanel>

</Grid>

SideModel is defined in the SidePannel.xaml.cs.

    public partial class SidePanel : UserControl
{
    public static DependencyProperty SideModelProperty;


    static SidePanel()
    {
        SideModelProperty = DependencyProperty.Register("SideModel", typeof(SidePannelModel), typeof(SidePanel)); 
    }

    public SidePanel()
    {
        InitializeComponent();

    }


    public SidePannelModel SideModel 
    {
         get
        {
            return (SidePannelModel)GetValue(SideModelProperty);
        }
        set
        {
            SetValue(SideModelProperty, value);
        }
    }

}

But the SidePanel controller is not loaded with the Words I am expecting.

appropriate part of SidePanel.xaml is given below.

<UserControl x:Class="ThaiDictionary.SidePanel"
         x:Name="SidePannelController"
         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" 
         xmlns:l="clr-namespace:ThaiDictionary"
         mc:Ignorable="d" MinHeight="300" MinWidth="300" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Background="Azure">
<UserControl.Resources>

</UserControl.Resources>

<DockPanel LastChildFill="True" DataContext="{Binding SidePModel}">
    <l:SearchTextBox SearchEventTimeDelay="00:00:02.00"  Text="{Binding  ElementName= SidePannelController,  Path= SearchWord, Mode=TwoWay}" DockPanel.Dock="Top"  Search="SearchTextBox_Search" HorizontalAlignment="Stretch" Background="Bisque"/>
    <ListBox Name="LeftSidePnel1" ItemsSource="{Binding  ElementName= SidePannelController,  Path= Language1, Mode=TwoWay}" HorizontalAlignment="Stretch"
         VerticalAlignment="Stretch" ScrollViewer.CanContentScroll="True" ScrollViewer.VerticalScrollBarVisibility="Visible" ItemTemplate="{DynamicResource WordTemplate}" MinHeight="266" Height="auto" >
        <ListBox.Resources>
            <DataTemplate x:Key="WordTemplate">
                <Label Content="{Binding Word}" HorizontalAlignment="Left" VerticalAlignment="Top" Width="auto"/>
            </DataTemplate>
        </ListBox.Resources>
    </ListBox>
</DockPanel>

But when I run the project I can not see the words loaded in to the Sidepanel usercontrol. What is wrong with this code. I can not find a way out here. Can you give me some quick help.

Edit:

I have followed the naming conventions and changed the SidePannel.xaml.cs.

Binding error:

 System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=SidePanelController'. BindingExpression:Path=SearchWord; DataItem=null; target element is 'SearchTextBox' (Name=''); target property is 'Text' (type 'String')
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=SidePanelController'. BindingExpression:Path=Language1; DataItem=null; target element is 'ListBox' (Name='LeftSidePnel1'); target property is 'ItemsSource' (type 'IEnumerable')

I have added the full SidePanel.xaml and I have changed the ElementName to SidePannelController as in the xaml file. But it still not getting loading the words

New Edit:

    System.Windows.Data Information: 41 : BindingExpression path error: 'SearchWord' property not found for 'object' because data item is null.  This could happen because the data provider has not produced any data yet. BindingExpression:Path=SideModel.SearchWord; DataItem='SidePanel' (Name='SidePannelController'); target element is 'SearchTextBox' (Name=''); target property is 'Text' (type 'String')
System.Windows.Data Information: 20 : BindingExpression cannot retrieve value due to missing information. BindingExpression:Path=SideModel.SearchWord; DataItem='SidePanel' (Name='SidePannelController'); target element is 'SearchTextBox' (Name=''); target property is 'Text' (type 'String')
System.Windows.Data Information: 21 : BindingExpression cannot retrieve value from null data item. This could happen when binding is detached or when binding to a Nullable type that has no value. BindingExpression:Path=SideModel.SearchWord; DataItem='SidePanel' (Name='SidePannelController'); target element is 'SearchTextBox' (Name=''); target property is 'Text' (type 'String')
System.Windows.Data Information: 10 : Cannot retrieve value using the binding and no valid fallback value exists; using default instead. BindingExpression:Path=SideModel.SearchWord; DataItem='SidePanel' (Name='SidePannelController'); target element is 'SearchTextBox' (Name=''); target property is 'Text' (type 'String')
System.Windows.Data Information: 41 : BindingExpression path error: 'Language1' property not found for 'object' because data item is null.  This could happen because the data provider has not produced any data yet. BindingExpression:Path=SideModel.Language1; DataItem='SidePanel' (Name='SidePannelController'); target element is 'ListBox' (Name='LeftSidePnel1'); target property is 'ItemsSource' (type 'IEnumerable')
System.Windows.Data Information: 20 : BindingExpression cannot retrieve value due to missing information. BindingExpression:Path=SideModel.Language1; DataItem='SidePanel' (Name='SidePannelController'); target element is 'ListBox' (Name='LeftSidePnel1'); target property is 'ItemsSource' (type 'IEnumerable')
System.Windows.Data Information: 21 : BindingExpression cannot retrieve value from null data item. This could happen when binding is detached or when binding to a Nullable type that has no value. BindingExpression:Path=SideModel.Language1; DataItem='SidePanel' (Name='SidePannelController'); target element is 'ListBox' (Name='LeftSidePnel1'); target property is 'ItemsSource' (type 'IEnumerable')

Thanks

diyoda_
  • 5,274
  • 8
  • 57
  • 89
  • Maybe all you have to do is correcting your DependencyProperty declaration because of Dependency Property Name Conventions. Please see my answer [here](http://stackoverflow.com/a/16404640/620360). – LPL May 07 '13 at 17:20
  • @LPL I have followed the naming conventions properly but the problem is the same. – diyoda_ May 07 '13 at 17:40
  • Are you getting any binding errors in your `Output` window? Also, you're binding to an element named `SidePannelController2` - can you show the full XAML for where that control is and where the `SidePanel` `UserControl` referencing it is? I suspect your problem may be that the binding can't find an element named `SidePannelController2` further up the VisualTree from your `SidePanel` – Rachel May 07 '13 at 17:47
  • @Rachel I have added the full XAML. Changed the ElementName as well. – diyoda_ May 07 '13 at 18:10

2 Answers2

1

Language1 and SearchWord are not properties on your UserControl, they're properties on your UserControl.SideModel property.

So change your bindings to include SideModel in your Path property, so it correctly binds to SidePannelController.SideModel.Language1 (or SearchWord), like this:

ItemsSource="{Binding ElementName=SidePannelController, Path=SideModel.Language1}"

But I suspect you're not showing your actual XAML, because your binding error says "Cannot find source for binding", which means it can't find an element named SidePannelController in the VisualTree (since ElementName specifies the source to use for the binding).

If that's the case, you can try using a RelativeSource binding to find the UserControl instead of ElementName

ItemsSource="{Binding Path=SideModel.Language1,
    RelativeSource={RelativeSource AncestorType={x:Type l:SidePanel}}"
Rachel
  • 130,264
  • 66
  • 304
  • 490
  • Thank you a lot. Problem solved, One more thing, Even though the words are loaded to the sidepannel, The out put window still shows a binding error. as shown in the new Edit.Do you know what causes this problem? – diyoda_ May 07 '13 at 18:34
  • @Diode You get a binding error anytime a binding tries to evaluate to a value and fails. There are many reasons it could be failing, however the most common is that the `DataContext` (data item) is incorrect. I wrote a SO answer recently about [debugging WPF binding errors](http://stackoverflow.com/a/14523290/302677) that you may find useful. To summarize, break up your error by the colons/semicolons, and read it backwards to understand the exact location of the error and problem. – Rachel May 07 '13 at 18:41
  • Wow thank you for a very constructive and detailed and dedicated answer. Appreciate a lot(Up Vote + Correct Answer + Up vote for related answer), Hope you give some help on WPF in the future as well. :) – diyoda_ May 07 '13 at 18:58
-1

I don't know what DictionaryModel is.

Maybe a typo, but it's possible you have an extra }, in MainWindow.xaml.cs right before:

Language2 = new List<WordModel>()

That would mean that Language2 is not a member of dictionary.SideModel, but instead is another, separate element of the collection (a sibling property of SideModel?)

However, in MainWindow.xaml, you are Binding to Language2 inside of a binding to SideModel. Since Language2 isn't a child of SideModel, XAML can't resolve the binding.

klugerama
  • 3,312
  • 19
  • 25