1

Ok, we are trying out XAML for our GUI now (and learning as we go)...I have been able to do the data binding without a problem in XAML and C# independent of one another, but now comes the time I need to pass values back and forth and I'm a bit lost. When I compile and try to navigate to the page, it is throwing a XamlParseException: Specified class name doesn't match actual root instance type. Remove Class directive or provide an instance via XamlObjectWriterSettings.RootObjectInstance. Line 5 position 2.

Any help or a gentle shove in the right direction is greatly appreciated :)

Here's where I am:

namespace TheAirline.GraphicsModel.PageModel.PageFinancesModel
{
    /// <summary>
    /// Interaction logic for PageFinances.xaml
    /// </summary>
    public partial class PageFinances : Page
    {
        private Airline Airline;

        public PageFinances(Airline airline)
        {
            InitializeComponent();
            this.Language = XmlLanguage.GetLanguage(new   CultureInfo(AppSettings.GetInstance().getLanguage().CultureInfo, true).IetfLanguageTag);

            this.Airline = airline;
            Page page = null;
//loading the XAML
          using (FileStream fs = new FileStream("TheAirline\\GraphicsModel\\PageModel  \\PageFinancesModel\\PageFinances.xaml", FileMode.Open, FileAccess.Read))
            {
            page = (Page)XamlReader.Load(fs);
            }
//finding XAML element and trying to set the value to a variable
          string airlineCash = GameObject.GetInstance().HumanAirline.Money.ToString();
          TextBox cashValue = (TextBox)page.FindName("cashValue");
          cashValue.DataContext = airlineCash;
        }
    }
}

And the first few lines of the XAML:

<Page
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"      
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"   
    xmlns:AirlineModel="clr-namespace:TheAirline.Model.AirlineModel"
    mc:Ignorable="d"
x:Class="TheAirline.GraphicsModel.PageModel.PageFinancesModel.PageFinances"
    xmlns:c="clr-namespace:TheAirline.GraphicsModel.Converters"
...>
</Page>
mikedugan
  • 2,393
  • 3
  • 19
  • 24
  • Your statement `I have been able to do the data binding without a problem in XAML and C# independent of one another, but now comes the time I need to pass values back and forth and I'm a bit lost` is completely contradictory. If you `DataBind`, the `DataBinding` `ITSELF` is passing data back and forth. I don't understand what you mean. Also, you're not supposed to do things like `TextBox cashValue = (TextBox)page.FindName("cashValue");` and `cashValue.DataContext = airlineCash;`. Please specify what you need and we can help you. – Federico Berasategui Mar 10 '13 at 09:14
  • Sorry if that was a bit vague (and contradictory) - still learning the ins and outs of XAML. Anyway - I meant I am able to bind the value of a slider to a textbox within XAML or c# exclusively, but not able to bind a value created in XAML to a variable in c# or vice versa. I hope that makes more sense :) – mikedugan Mar 10 '13 at 10:08

1 Answers1

1

Bindings in XAML are resolved against the object that is assigned to the DataContext property of any given XAML element. The value of that property (as well as many other properties) Is Inherited in any given Visual Tree from parent elements to child elements.

for instance, given this class:

public namespace MyNamespace
{
    public class ViewModel
    {
        public string Name {get;set;}
        public bool IsActive {get;set;}
    }
}

and this XAML:

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:MyNamespace"
        FontSize="20">
   <Window.DataContext>
       <local:ViewModel>
   </Window.DataContext>
   <StackPanel>
       <TextBox Text="{Binding Path=Name}"/>
       <CheckBox IsChecked="{Binding Path=IsActive}"/>
   <StackPanel>
</Window>

All four objects defined in XAML, the Window, the StackPanel, the TextBox, and the CheckBox, will have a FontSize of 20, and the instance of the ViewModel class assigned to their DataContext property. Therefore all bindings (Except bindings with a specified ElementName, RelativeSource, or Source) will be resolved against that instance.

It would be exactly the same if the property was assigned in code instead of in XAML:

public MyWindow() //Window Constructor
{
    InitializeComponent();
    this.DataContext = new ViewModel(); //Note that keyword "this" is redundant, I just explicity put it there for clarity.
}

Because of this, there is no need to set the DataContext property to each element explicitly, as the framework is already taking care of that.

Also, notice that in XAML, most built-in Markup Extensions have a default constructor convention that allows you to abbreviate their usage. In the case of the Binding Markup Extension, the default constructor has the Path property, therefore this:

<TextBox Text="{Binding Path=Name}"/>

is exactly the same as this:

<TextBox Text="{Binding Name}"/>

Now, for property changes in the underlying DataContext to be automatically passed from the binding source (ViewModel) to the binding target (XAML-defined objects), the source object must implement the System.ComponentModel.INotifyPropertyChanged interface and raise the PropertyChanged event every time a property changes.

Therefore, in order to support Two-Way Binding, the example class should look like this:

public namespace MyNamespace
{
    public class ViewModel: INotifyPropertyChanged
    {
        private string _name;
        public string Name 
        {
            get
            {
                return _name;
            }
            set
            {
                _name = value;
                NotifyPropertyChanged("Name");
            }
        }

        private bool _isActive;
        public bool IsActive
        {
            get
            {
                return _isActive;
            }
            set
            {
                _isActive = value;
                NotifyPropertyChanged("IsActive");
            }
        }
    }

    public void NotifyPropertyChanged (string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName);
    }
}

Notice that the ViewModel class has no dependency or direct reference to any of the XAML-defined objects, but still it contains the Values of the properties that will appear in the UI. This allows for a complete decoupling between UI and application logic/data known as the MVVM Pattern. I strongly suggest you research on that topic if you expect to be successful in programming in C# + XAML, because it is a radical mindshift when compared to other, traditional UI paradigms.

For example, something like this is not recommended in XAML-based applications:

if (myWindow.CheckBox1.IsChecked)
    //Do Something

because that would mean that you're coupling the application logic and making it dependant on the state of UI elements, which is precisely what you need to avoid.

Notice that all the links and all the concepts referenced in this answer pertain to WPF, but are also applicable to Silverlight and WinRT. Since you did not specify which of the three XAML-based frameworks you're using, I posted the WPF ones, which is what I'm most familiar with.

Community
  • 1
  • 1
Federico Berasategui
  • 43,562
  • 11
  • 100
  • 154
  • Thanks for the answer. I found that my problem locally was something rather simple, but your answer provided a lot of background information I didn't already have :) – mikedugan Mar 16 '13 at 14:41